iframe-insluitingscontrole
Gratis online iframe-checker: voer een willekeurige pagina-URL in om de X-Frame-Options- en Content-Security-Policy frame-ancestors-headers te inspecteren, bekijk of de pagina in een iframe kan worden ingebed en bevestig dit met een live voorbeeld. De geschiedenis wordt bewaard gedurende de huidige browsersessie.
Geschiedenis (deze sessie)
Alleen opgeslagen in dit tabblad (sessionStorage); wordt verwijderd bij het sluiten van het tabblad. Er wordt geen data naar de server verstuurd.
Hoe de controle werkt
- Voer de doel-URL in en klik op Controleren. De server haalt de pagina op als een standaard iframe-verzoek (met Sec-Fetch-Dest: iframe) en analyseert de responsheaders.
- Het eindoordeel wordt bepaald door X-Frame-Options (DENY/SAMEORIGIN blokkeert framers) en Content-Security-Policy frame-ancestors (alleen * of een schema-wildcard staat willekeurige derden toe als ouder-element).
- Dezelfde URL wordt geladen in het live-preview iframe, zodat je kunt bekijken hoe de browser hiermee omgaat, inclusief JavaScript frame-busting die niet zichtbaar is in de headers.
Wat bepaalt of een pagina kan worden ingebed?
Of een webpagina in een <iframe> op een andere site getoond mag worden, beslist de browser aan de hand van de antwoordheaders die de pagina zelf retourneert. Deze scanner voert exact dezelfde inspectie server-side uit en geeft je direct uitsluitsel.
X-Frame-Options is de klassieke header: DENY verbiedt framing op alle pagina's, SAMEORIGIN staat alleen pagina's van dezelfde oorsprong toe om hem te omvatten, en ALLOW-FROM is uit moderne browsers geschrapt. Wanneer deze header ontbreekt, blokkeren verouderde regels de framing niet.
Content-Security-Policy frame-ancestors is de moderne vervanger. Het specificeert welke oorsprongen de pagina mogen insluiten — bijvoorbeeld frame-ancestors 'self' https://example.com. Een waarde van * (of enkel een protocol zoals https:) staat insluiting via elke HTTPS-containerpagina toe; elk restrictiever beleid blokkeert insluiting door derden.
Headers vertellen niet het gehele verhaal: scripts op de pagina kunnen anti-framebusting-code uitvoeren (door `top !== self` te vergelijken en te forceren dat er naar de hoofdpagina wordt genavigeerd), en inlogpagina's of geo-beperkte eindpunten kunnen anders reageren op verzoeken vanuit datacenters. Daarom wordt elk resultaat gekoppeld aan een live-voorbeeld.
Snelle gids: configuratie van responsheaders
Als je eigenaar van de site bent, beheer de framing direct via antwoordheaders.
Insluiting vanuit elke pagina blokkeren
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'
Browsers weigeren de pagina weer te geven in een iframe — dit biedt de strengste clickjacking-bescherming.
Alleen insluiting vanaf dezelfde oorsprong toestaan
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
Alleen pagina's met hetzelfde protocol, host en poort mogen deze omvatten; externe websites worden geblokkeerd.
Alleen insluiting vanaf specifieke oorsprongen toestaan
Content-Security-Policy: frame-ancestors 'self' https://trusted.example.com
Vermeld vertrouwde oorsprongen in frame-ancestors; niet-opgenomen oorsprongen worden geblokkeerd.
Insluiting vanuit elke pagina toestaan
X-Frame-Options niet instellen
Content-Security-Policy: frame-ancestors *
Elke site kan de pagina in een iframe tonen. Evalueer de veiligheidsafweging hierbij zorgvuldig.
Opmerking: X-Frame-Options wordt vervangen door CSP frame-ancestors. Indien beide aanwezig zijn, heeft CSP voorrang — geef de voorkeur aan frame-ancestors.
Hoe detecteert de server dat een verzoek vanuit een iframe komt?
Sinds circa 2020 koppelen browsers op basis van Chromium en Firefox automatisch een set Fetch Metadata-verzoekheaders aan elke navigatie- en subresource-aanvraag. De meest nuttige hiervoor bij framingscontroles is Sec-Fetch-Dest — deze informeert de server in welke context het bronbestand werd opgevraagd, zonder dat de aanvragende pagina daar actief mee hoeft samen te werken.
- Sec-Fetch-Dest: document — navigatie op toppagina-niveau, niet binnen een frame.
- Sec-Fetch-Dest: iframe — het verzoek wordt geladen binnen een <iframe>-element.
- Sec-Fetch-Dest: frame — geladen binnen een verouderd <frame>-element (frameset).
- Sec-Fetch-Dest: embed / object — geladen binnen een <embed>- of <object>-element.
Deze tester stuurt een eigen probe met `Sec-Fetch-Dest: iframe`, exact zoals een echte browser dat doet bij het inbedden van een pagina. Het oordeel weerspiegelt daarom hoe de doelserver daadwerkelijk reageert op echte iframe-verzoeken, in plaats van alleen op een algemene fetch.
`Sec-Fetch-Dest` is een nuttig signaal, maar vormt geen beveiligingslimiet: deze wordt uitsluitend door moderne browsers verzonden. Clients buiten de browser — zoals cURL, bots, bepaalde webviews en oudere browsers — kunnen deze helemaal weglaten of een willekeurige waarde versturen. Een server kan hierop loggen of throttlen, maar mag er nooit uitsluitend op vertrouwen om te bepalen of het inbedden veilig is. De uiteindelijke beslissing ligt bij `X-Frame-Options` en `CSP frame-ancestors`, die browsers afdwingen ongeacht de verzoekheaders.
Aan de kliantzijde kan een pagina ook detecteren dat deze in een frame draait, zelfs zonder specifieke headers. Dit gaat bijvoorbeeld door `window.top !== window.self` te controleren (of `window.frameElement` uit te lezen bij same-origin frames), waarna gereageerd kan worden — door een waarschuwing te tonen of een redirect naar de hoofdweergave af te dwingen. Dit is de eerder genoemde 'frame-busting'-techniek, die werkt ongeacht de inhoud van de verzoekheaders.
Voorbeelden van serverconfiguratie: iframe-inbedden blokkeren
De onderstaande fragmenten laten zien hoe je elke server of framework configureert om iframe-insluiting volledig te blokkeren (X-Frame-Options: DENY + CSP frame-ancestors 'none') — de strengste variant uit de recepten uit de snelle gids hierboven.
server {
location / {
add_header X-Frame-Options "DENY" always;
add_header Content-Security-Policy "frame-ancestors 'none'" always;
}
}
<IfModule mod_headers.c>
Header always set X-Frame-Options "DENY"
Header always set Content-Security-Policy "frame-ancestors 'none'"
</IfModule>
app.use((req, res, next) => {
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('Content-Security-Policy', "frame-ancestors 'none'");
next();
});
// next.config.js
module.exports = {
async headers() {
return [
{
source: '/:path*',
headers: [
{ key: 'X-Frame-Options', value: 'DENY' },
{ key: 'Content-Security-Policy', value: "frame-ancestors 'none'" },
],
},
];
},
};
class SetFrameOptions
{
public function handle(Request $request, Closure $next): Response
{
$response = $next($request);
$response->headers->set('X-Frame-Options', 'DENY');
$response->headers->set('Content-Security-Policy', "frame-ancestors 'none'");
return $response;
}
}
export default {
async fetch(request) {
const response = await fetch(request);
const headers = new Headers(response.headers);
headers.set('X-Frame-Options', 'DENY');
headers.set('Content-Security-Policy', "frame-ancestors 'none'");
return new Response(response.body, { status: response.status, headers });
},
};
Wil je alleen je eigen site, of een korte whitelist, toestaan om de pagina te omvatten in plaats van iedereen te blokkeren? Vervang DENY door SAMEORIGIN, en 'none' door 'self' of een expliciete lijst van oorsprongen — de overige configuratie blijft onveranderd.
Bekende valkuilen per platform
Los van de algemene headerregels hanteren sommige bekende platforms eigen specifieke gedragingen. Het is goed om dit te weten voordat je puur op basis van headers beslist of iets 'geblokkeerd' of 'inbedbaar' is.
| Platform / scenario | Gedrag | Waarom |
|---|---|---|
| YouTube-watchpagina (youtube.com/watch) | Geblokkeerd | Gebruik in plaats daarvan de officiële `youtube.com/embed/{id}`-speler-URL. De standaard kijkpagina hanteert namelijk een restrictief frameringbeleid. |
| Google Maps-locatiepagina | Geblokkeerd | Alleen de iframe-URL van de Maps Embed API (`google.com/maps/embed`) is specifiek ontworpen om ingebed te worden. |
| OAuth-inlogpagina's van Google / Microsoft | Geblokkeerd | Bewust geblokkeerd sinds 2015 om phishing van inloggegevens via iframes te voorkomen. Het inlogproces moet altijd in een hoofdscherm of pop-upvenster plaatsvinden. |
| Betaal- en afhandelingspagina's (Stripe Checkout, PayPal, de meeste bankportalen) | Geblokkeerd | Het invoegen van betaalformulieren in een frame is een klassiek clickjacking-middeltje, waardoor betalingsverwerkers dit standaard blokkeren. |
| GitHub-repository- en bestandspagina's | Geblokkeerd | De instelling voor `frame-ancestors` geldt sitebreed als 'none'. Gebruik liever de REST- of GraphQL-API of maak gebruik van een screenshot. |
| Notion- en Google Docs-pagina's ('Publiceren op internet') | Inbedbaar | Deze zijn expliciet ontworpen om ingebed te worden en bieden kant-en-klare inbedcodes aan. |
| Wikipedia-artikelen | Inbedbaar | Standaard zijn er geen restrictieve `X-Frame-Options` of CSP-instellingen, maar controleer wel de licentie- en creditvoorwaarden voordat je ze massaal wilt inbedden. |
Veelvoorkomende toepassingen
- Bepaal eerst of widgets, dashboards of documenten van derden in jouw product ingebed kunnen worden voordat je code voor de integratie gaat schrijven.
- Verifieer of jouw eigen website correct de beoogde `X-Frame-Options`- of CSP `frame-ancestors`-policy verstuurt.
- Debug clickjacking-bescherming: begrijp waarom een pagina binnen een iframe over about:blank of een weigermelding wordt weergegeven.
- Controleer kandidaat-URLs batchsgewijs tijdens inhoudsamenvoeging of portaalintegratie, waarbij je de sessiegeschiedenis gebruikt om resultaten opnieuw te bekijken.
- Bereid je voor op beveiligingsreviews of penetration tests door het frameerbeleid van externe afhankelijkheden te documenteren.