Changeset 29eb745 in Klonkt for src/services/ActivityPubService.js
- Timestamp:
- 08/08/2026 08:53:20 PM (4 weeks ago)
- Branches:
- main
- Children:
- dc0da72
- Parents:
- ea211b9
- git-author:
- Robin <roboburr@…> (08/08/2026 08:53:18 PM)
- git-committer:
- roboburr <roboburr@…> (08/08/2026 08:53:20 PM)
- File:
-
- 1 edited
-
src/services/ActivityPubService.js (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/services/ActivityPubService.js
rea211b9 r29eb745 110 110 return true; // not an IP literal we recognise → refuse 111 111 } 112 /** 113 * Uitzonderingen op de SSRF-poort, voor een testkudde op de eigen machine 114 * (shaer-6wt: honderd wards met een guardian, Barts opdracht 8-8). 115 * 116 * WAAROM DIT MAG BESTAAN. De bescherming hierboven is er omdat een actor-URI van 117 * een VREEMDE komt: een aanvaller die "http://169.254.169.254/" doorgeeft laat 118 * ons zijn werk doen. Deze lijst gaat niet over vreemden -- hij staat in de 119 * omgeving van deze server, wordt door de beheerder gezet, en is leeg tenzij 120 * iemand hem expliciet vult. 121 * 122 * WAAROM HIJ ZO SMAL IS. Geen vlag die "loopback is oke" zegt, maar een lijst 123 * van precieze host:poort-paren. `[::1]:3060` opent niet 127.0.0.1, niet poort 124 * 3061, en niets in het interne netwerk. Een brede vlag zou de bescherming in 125 * een dev-omgeving uitzetten, en dev-omgevingen worden productie. 126 * 127 * AP_ALLOW_HOSTS="[::1]:3060,[::1]:3061" 128 */ 129 const AP_ALLOW_HOSTS = new Set( 130 String(process.env.AP_ALLOW_HOSTS || '').split(',').map((x) => x.trim().toLowerCase()).filter(Boolean), 131 ); 132 function isAllowedTestHost(u) { 133 if (!AP_ALLOW_HOSTS.size) return false; 134 return AP_ALLOW_HOSTS.has(u.host.toLowerCase()); 135 } 112 136 async function assertPublicHost(hostname) { 113 if (net.isIP(hostname)) { if (isBlockedIp(hostname)) throw new Error('ssrf-blocked-ip'); return; } 114 const addrs = await dns.promises.lookup(hostname, { all: true }); 137 // URL.hostname geeft een IPv6-literal MET blokhaken ("[::1]"), en net.isIP 138 // herkent die vorm niet. Zonder strippen viel elk IPv6-adres door naar de 139 // DNS-tak, waar het strandde op ENOTFOUND: geweigerd, maar per ongeluk en met 140 // de verkeerde reden. isBlockedIp strippde ze al -- die verwachtte dus input 141 // die hier nooit aankwam. 142 const naakt = String(hostname || '').replace(/^\[|\]$/g, ''); 143 if (net.isIP(naakt)) { if (isBlockedIp(naakt)) throw new Error('ssrf-blocked-ip'); return; } 144 const addrs = await dns.promises.lookup(naakt, { all: true }); 115 145 if (!addrs.length || addrs.some((a) => isBlockedIp(a.address))) throw new Error('ssrf-blocked-host'); 116 146 } … … 128 158 const u = new URL(target); // throws on malformed → caller's catch 129 159 if (u.protocol !== 'https:' && u.protocol !== 'http:') throw new Error('ssrf-bad-scheme'); 130 await assertPublicHost(u.hostname); 160 // Alleen op de precieze host:poort uit AP_ALLOW_HOSTS, en per hop opnieuw: 161 // een omleiding naar een ANDER intern adres blijft geweigerd. 162 if (!isAllowedTestHost(u)) await assertPublicHost(u.hostname); 131 163 const r = await fetch(target, { 132 164 ...opts,
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)