Iframe-embedding toestaan voor een partner
Aan het einde van deze gids kan een vertrouwde partner-origin de Tapster-frontend in een <iframe> laden, en is dat lokaal en in productie bevestigd.
Voorwaarden:
- Je hebt schrijftoegang tot deze repo en kunt een PR mergen.
- Je kent de exacte origin van de partner (scheme + host, bijvoorbeeld
https://klant.nlofhttps://*.partner.nl). Geen pad, geen trailing slash. - De partner-origin gebruikt HTTPS. HTTP is niet toegestaan in productie.
- Docker en
npmzijn beschikbaar als je lokaal wilt testen.
Achtergrond
De frontend-nginx zet één security-header die iframe-embedding bepaalt:
add_header Content-Security-Policy "frame-ancestors 'self' <partner-origins>" always;
'self' betekent: alleen Tapster zelf mag zichzelf embedden. Elke origin die je achter 'self' zet, wordt extra toegestaan. Browsers blokkeren alle andere origins met een console-melding van het type “Refused to display … in a frame because an ancestor violates the Content Security Policy directive”.
X-Frame-Options staat bewust niet meer in de config: die kan geen allowlist met meerdere origins uitdrukken, en moderne browsers honoreren CSP frame-ancestors er toch boven.
1. Voeg de origin toe aan nginx.conf
Open apps/frontend/nginx.conf en pas de Content-Security-Policy-regel aan. Voorbeeld voor één partner:
- add_header Content-Security-Policy "frame-ancestors 'self'" always;
+ add_header Content-Security-Policy "frame-ancestors 'self' https://klant.nl" always;
Meerdere origins zijn spatie-gescheiden:
add_header Content-Security-Policy "frame-ancestors 'self' https://klant.nl https://*.partner.nl" always;
Regels:
- Gebruik altijd
https://. - Geen pad of query (
https://klant.nl/portaalis ongeldig en wordt door browsers genegeerd). - Wildcard mag alleen op subdomein-niveau:
https://*.partner.nlis goed,https://*.nlniet. - Schrijf elke origin uit (geen variabelen of placeholders), zodat de header bij elke
nginx -s reloaden incurl -Idirect verifieerbaar is.
2. Test lokaal
Vanuit de repo-root:
docker build -f apps/frontend/Dockerfile -t tapster-frontend-csp-test .
docker run --rm -d --name csp-test -p 8080:80 \
-e URL_API=http://localhost:3000 \
-e URL_APIV6=http://localhost:3000 \
tapster-frontend-csp-test
Controleer de header:
curl -sI http://localhost:8080/ | grep -i content-security-policy
Verwachte output (één regel, met jouw allowlist):
content-security-policy: frame-ancestors 'self' https://klant.nl
Maak optioneel een minimale embed-test:
cat > /tmp/embed-test.html <<'EOF'
<!doctype html><meta charset="utf-8"><title>embed-test</title>
<iframe src="http://localhost:8080/" style="width:100%;height:90vh;border:0"></iframe>
EOF
open /tmp/embed-test.html
Open de DevTools-console van die pagina. Geen CSP-foutmelding betekent dat embedding werkt voor die origin. (Voor de echte partner-origin moet je de src= invullen met de productie-frontend-URL en het testbestand serveren vanaf de partner-origin, anders test je alleen 'self'.)
Opruimen:
docker stop csp-test
3. PR aanmaken en mergen
Volg de standaard PR-flow (feat/-branch, conventional commit, automatische PR via CI). Vermeld in de PR-beschrijving:
- Welke partner-origin is toegevoegd.
- Op welke datum de partner is geverifieerd.
- Een link naar de afspraak of ticket waarin de embedding is toegezegd.
4. Verifieer in productie
Na deploy:
curl -sI https://app.tapster.nl/ | grep -i content-security-policy
De allowlist moet exact bevatten wat je in stap 1 hebt toegevoegd. Vraag de partner kort te bevestigen dat hun pagina de Tapster-frontend toont zonder iframe-foutmelding in de browser-console.
Een origin weer intrekken
Verwijder de origin uit dezelfde regel in apps/frontend/nginx.conf, open een nieuwe PR, en herhaal stap 2 en 4. Communiceer de intrekking vooraf met de partner, anders breekt hun pagina zonder waarschuwing.
Veelvoorkomende fouten
- Origin met pad of trailing slash.
https://klant.nl/ofhttps://klant.nl/portaalwerkt niet; gebruikhttps://klant.nl. http://in productie. Browsers staan mixed-content iframes niet toe; gebruik altijd HTTPS.- Wildcard op TLD-niveau.
https://*.nlis ongeldig, gebruikhttps://*.klantgroep.nl. - Vergeten dat cookies een
SameSite=None; Secure-attribuut nodig hebben als de partner-origin afwijkt van Tapster zelf en de gebruiker binnen de iframe ingelogd moet zijn. Check eerst of dat voor jouw use-case van toepassing is.