# X-Frame-Options vs frame-ancestors, quel contrôle anti-clickjacking utiliser (/fr/blog/x-frame-options-vs-frame-ancestors)



Les deux répondent à la même question : qui a le droit de placer votre page dans
une frame, ce qui est le contrôle qui stoppe le clickjacking. La directive
[`frame-ancestors`](/fr/docs/web-security/policies/content-security-policy/directives/frame-ancestors)
de la [politique de sécurité du contenu (CSP)](/fr/docs/web-security/policies/content-security-policy)
est la version moderne et plus expressive ;
[`X-Frame-Options`](/fr/docs/web-security/security-headers/x-frame-options)
est le header plus ancien, conservé pour les clients qui n'ont jamais implémenté
la CSP. Envoyez les deux. Ils ne peuvent pas entrer en conflit : tout navigateur
qui applique `frame-ancestors` doit, selon la spec CSP, ignorer
`X-Frame-Options`, donc la directive CSP décide sur les navigateurs modernes et
le header plus ancien couvre le reste.

## La menace du clickjacking [#la-menace-du-clickjacking]

Le clickjacking est une attaque où l'attaquant charge votre page dans une frame
sur un site qu'il contrôle, généralement invisible ou transparente, et dépose son
propre appât par-dessus. La victime croit cliquer sur un bouton de la page de
l'attaquant, mais le clic atterrit sur votre page framée : confirmer un paiement,
changer un réglage, approuver une permission. La défense est d'indiquer au
navigateur quels sites, s'il y en a, peuvent framer votre page. Les deux
contrôles ci-dessous font exactement cela.

## X-Frame-Options, le header d'origine [#x-frame-options-le-header-dorigine]

`X-Frame-Options` est le header anti-clickjacking d'origine, documenté dans la
RFC 7034. Il a deux valeurs qui fonctionnent encore.

* `DENY` : aucun site ne peut framer la page. MDN précise que la page "cannot be
  loaded in any frame, regardless of origin", donc même votre propre site ne
  peut pas la framer.
* `SAMEORIGIN` : seules les pages de la même origine peuvent la framer.

```http
X-Frame-Options: DENY
```

Une nuance sur `SAMEORIGIN`. Les navigateurs modernes vérifient chaque ancêtre de
la chaîne de frames, donc une frame same-origin imbriquée dans une page hostile
reste bloquée. La RFC 7034 documentait que les premières implémentations ne
vérifiaient que le contexte de navigation de premier niveau, ce qui laissait
cette astuce d'imbrication ouverte ; les moteurs actuels la ferment.

Malgré son âge, le header n'est pas déprécié. En janvier 2025, les éditeurs de la
spec HTML ont délibérément retiré les mots "legacy" et "obsoleted by" de sa
description du header, et la spec CSP dit désormais que `frame-ancestors`
"overrides" (l'emporte sur) `X-Frame-Options` plutôt que "obsoletes" (le rend
obsolète). Tous les navigateurs l'appliquent encore, et rien ne prévoit de le
retirer.

### ALLOW-FROM est obsolète, et son échec laisse tout ouvert [#allow-from-est-obsolète-et-son-échec-laisse-tout-ouvert]

Le header a eu autrefois une troisième valeur, `ALLOW-FROM uri`, censée autoriser
une seule origine nommée. Elle a commencé comme une extension d'Internet
Explorer, n'a jamais été implémentée uniformément (les mots mêmes de la RFC
7034\), ne pouvait nommer qu'une seule origine sans wildcards, et Firefox, qui
l'avait aussi livrée, l'a retirée en 2019 en pointant vers `frame-ancestors`
comme remplacement.

Le point dangereux est sa façon d'échouer. Un navigateur qui ne reconnaît pas
`ALLOW-FROM` traite la valeur comme invalide et ignore le header entier. Le
message de console de Chromium le dit explicitement : "'ALLOW-FROM' is not a
recognized directive. The header will be ignored." Un site qui envoie aujourd'hui
uniquement `X-Frame-Options: ALLOW-FROM https://partner.example.com` n'a donc
aucune restriction de framing dans les navigateurs modernes, ce qui revient à
échouer en laissant tout ouvert (fail open) ; OWASP avertit qu'un site qui
dépend de `ALLOW-FROM` n'a aucune défense anti-clickjacking dans les navigateurs
qui ne le prennent pas en charge. Si vous devez autoriser des framers précis,
c'est le travail de `frame-ancestors`.

### Des valeurs contradictoires retombent sur deny [#des-valeurs-contradictoires-retombent-sur-deny]

Un piège associé pour les infrastructures en couches. Si deux couches posent des
valeurs différentes, disons que l'application envoie `SAMEORIGIN` et qu'un CDN
ajoute `DENY`, le navigateur reçoit des valeurs `X-Frame-Options`
contradictoires. Chromium traite cela comme une erreur et retombe sur `deny`,
refusant d'afficher la page dans toute frame. Quand un framing same-origin qui
fonctionnait casse après un changement d'infrastructure, les headers dupliqués
sont la première chose à vérifier.

## frame-ancestors, le remplaçant CSP [#frame-ancestors-le-remplaçant-csp]

`frame-ancestors` est arrivée avec CSP Level 2 et c'est la directive qui reprend
le travail. Au lieu de mots-clés fixes, elle prend une liste de sources :
`'none'`, `'self'`, et n'importe quel nombre de sources d'hôte ou de schéma, y
compris des sous-domaines wildcard comme `*.example.com`. C'est ce qui la rend
plus expressive. Vous pouvez autoriser plusieurs partenaires de confiance à la
fois, un arbre de sous-domaines entier, ou un schéma précis, ce que
`X-Frame-Options` ne peut exprimer dans aucun de ces cas. Les nonces et les
hashes ne s'y appliquent pas, puisqu'elle liste des parents de framing, pas des
scripts. Le navigateur vérifie chaque ancêtre de la chaîne de frames, et si un
seul d'entre eux échoue face à la liste, le chargement est annulé.

```http
Content-Security-Policy: frame-ancestors 'self' https://partner.example.com
```

Deux règles de déploiement comptent plus que tout le reste.

D'abord, elle n'a pas de fallback : `default-src` ne la couvre pas. MDN est
explicite : "a policy that declares `default-src 'none'` still allows the
resource to be embedded by anyone" (une politique qui déclare
`default-src 'none'` laisse quand même n'importe qui embarquer la ressource).
Une CSP verrouillée sans ligne `frame-ancestors` explicite ne dit rien sur le
framing, donc posez-la explicitement.

Ensuite, elle ne fonctionne qu'en header. La spec CSP exclut `frame-ancestors`
(avec `report-uri` et `sandbox`) de la livraison via
`<meta http-equiv="Content-Security-Policy">`, donc les navigateurs l'ignorent
dans une balise meta. Posez-la au niveau du serveur ou du CDN. Si vous voulez la
protection anti-clickjacking sans adopter une politique complète, voir
[comment poser frame-ancestors sans un header CSP complet](/fr/blog/frame-ancestors-without-csp-header).

Le support n'est plus une vraie contrainte : tous les moteurs modernes (Blink,
Gecko, WebKit) appliquent `frame-ancestors`. La seule lacune notable est
Internet Explorer, qui ne l'a jamais implémentée et ne comprend que
`X-Frame-Options`.

## La précédence, la règle exacte [#la-précédence-la-règle-exacte]

La spec CSP tranche ce qui se passe quand les deux headers arrivent sur la même
réponse : "If a resource is delivered with a policy that includes a directive
named frame-ancestors and whose disposition is 'enforce', then the
X-Frame-Options header MUST be ignored." Chromium l'implémente littéralement ;
son ancestor throttle laisse `frame-ancestors` décider à la place de
`X-Frame-Options` dès que la réponse porte une directive `frame-ancestors`
appliquée.

Notez le mot "enforce". Seule une `frame-ancestors` appliquée désactive
`X-Frame-Options`. Si vous testez la directive dans un header
[`Content-Security-Policy-Report-Only`](/fr/docs/web-security/policies/content-security-policy/report-only),
elle rapporte les violations mais ne supprime pas `X-Frame-Options`, donc le
header plus ancien continue d'appliquer pendant que vous observez les reports.
C'est exactement le comportement que vous voulez pendant un déploiement.

Cette règle de précédence est la raison pour laquelle envoyer les deux est sûr.
Il n'existe aucun état où les deux se combattent : les navigateurs qui
comprennent `frame-ancestors` l'utilisent et laissent tomber `X-Frame-Options`,
et les clients plus anciens qui précèdent CSP Level 2 lisent `X-Frame-Options`
seul. Les recommandations anti-clickjacking d'OWASP conseillent d'empiler des
défenses indépendantes pour la même raison.

## X-Frame-Options vs frame-ancestors côte à côte [#x-frame-options-vs-frame-ancestors-côte-à-côte]

| Capacité                                 | X-Frame-Options                                                                                             | frame-ancestors                                              |
| ---------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| N'autoriser aucun framing                | `DENY`                                                                                                      | `'none'`                                                     |
| N'autoriser que le framing same-origin   | `SAMEORIGIN`                                                                                                | `'self'`                                                     |
| Autoriser des origines externes précises | Impossible (`ALLOW-FROM` obsolète, échec ouvert)                                                            | `'self' https://partner.example.com`                         |
| Sous-domaines wildcard                   | Impossible                                                                                                  | `*.example.com`                                              |
| Ancêtres vérifiés                        | Toute la chaîne dans les navigateurs modernes (premier niveau seulement dans les premières implémentations) | Toute la chaîne, tout ancêtre en échec annule le chargement  |
| Définie via une balise meta              | Sans effet (header seulement)                                                                               | Sans effet (header seulement)                                |
| Couverte par `default-src`               | Non applicable                                                                                              | Non, à poser explicitement                                   |
| Quand les deux sont envoyés              | Ignoré là où une `frame-ancestors` appliquée est présente                                                   | L'emporte quand elle est appliquée                           |
| Support                                  | Tous les moteurs, y compris le vieil IE                                                                     | Tous les moteurs modernes (Blink, Gecko, WebKit) ; jamais IE |

## Recommandation [#recommandation]

Déployez les deux, avec le réglage le plus strict que votre site permet.
Utilisez `'none'` et `DENY` si rien ne devrait jamais framer votre page ;
utilisez `'self'` et `SAMEORIGIN` si votre propre application se frame
elle-même.

```http
Content-Security-Policy: frame-ancestors 'none'
```

```http
X-Frame-Options: DENY
```

N'utilisez jamais `ALLOW-FROM`, et retirez-le partout où vous le trouvez,
puisqu'il peut laisser une page sans aucune protection. Si vous devez autoriser
des partenaires nommés, exprimez-le uniquement dans `frame-ancestors` et gardez
`X-Frame-Options` à `SAMEORIGIN` ou `DENY` pour les vieux clients qui ne peuvent
de toute façon pas lire l'allowlist. Vous pouvez confirmer que les deux headers
sont présents et bien formés avec le
[scanner de headers de sécurité](/tools/security-headers) gratuit de CentralCSP.

Les deux headers diffèrent aussi après le déploiement, pas seulement en syntaxe : les
violations de `frame-ancestors` sont signalées via la Reporting API, et les refus de
`X-Frame-Options` ne le sont pas du tout. Pointer la CSP vers un endpoint CentralCSP
signifie qu'un site partenaire qui ne peut soudain plus vous intégrer apparaît comme une
csp-violation nommant l'origine qui encadre, plutôt que comme un ticket de support.

## FAQ [#faq]

### X-Frame-Options est-il déprécié ? [#x-frame-options-est-il-déprécié-]

Non. Ni MDN ni les données de compatibilité des navigateurs ne le marquent comme
déprécié, et tous les navigateurs l'appliquent encore. En janvier 2025, les
éditeurs de la spec HTML ont retiré les mots "legacy" et "obsoleted by" de sa
description, et la spec CSP dit désormais que `frame-ancestors` "overrides"
(l'emporte sur) le header plutôt que "obsoletes" (le rend obsolète). Seule la
valeur `ALLOW-FROM` est obsolète. Continuez d'envoyer le header à côté de
`frame-ancestors`.

### Faut-il utiliser à la fois X-Frame-Options et frame-ancestors ? [#faut-il-utiliser-à-la-fois-x-frame-options-et-frame-ancestors-]

Oui. Ils ne peuvent pas entrer en conflit, parce que la spec CSP exige que tout
navigateur appliquant `frame-ancestors` ignore `X-Frame-Options`. La directive
CSP décide donc sur tous les navigateurs modernes, et `X-Frame-Options` couvre
les vieux clients comme Internet Explorer qui n'ont jamais implémenté la CSP.
OWASP recommande d'empiler des défenses anti-clickjacking indépendantes, et
envoyer les deux headers coûte une ligne chacun.

### Pourquoi X-Frame-Options ALLOW-FROM ne fonctionne-t-il pas ? [#pourquoi-x-frame-options-allow-from-ne-fonctionne-t-il-pas-]

Parce qu'il est obsolète. Il a commencé comme une extension d'Internet Explorer,
n'a jamais été implémenté uniformément ailleurs, et Firefox l'a retiré en 2019.
Pire, un navigateur qui ne reconnaît pas `ALLOW-FROM` ignore le header entier,
donc la page échoue en laissant tout ouvert, sans aucune protection de framing.
Remplacez-le par
`Content-Security-Policy: frame-ancestors 'self' https://partner.example.com`.

### Puis-je poser frame-ancestors dans une balise meta ? [#puis-je-poser-frame-ancestors-dans-une-balise-meta-]

Non. Les navigateurs ignorent `frame-ancestors` dans une balise meta, et une
balise meta ne fonctionne pas non plus pour `X-Frame-Options`, donc posez les
deux au niveau du serveur ou du CDN. Pour les détails et les options de
déploiement, voir
[comment poser frame-ancestors sans un header CSP complet](/fr/blog/frame-ancestors-without-csp-header).

### frame-ancestors en mode Report-Only désactive-t-il X-Frame-Options ? [#frame-ancestors-en-mode-report-only-désactive-t-il-x-frame-options-]

Non. La règle de précédence ne s'applique qu'à une politique "whose disposition
is 'enforce'" (dont la disposition est "enforce"), donc une directive
`frame-ancestors` dans un header `Content-Security-Policy-Report-Only` rapporte
les violations pendant que `X-Frame-Options` continue d'appliquer. Cela fait de
Report-Only une façon sûre de tester une allowlist avant de l'activer.

## Lectures liées [#lectures-liées]

* [frame-ancestors](/fr/docs/web-security/policies/content-security-policy/directives/frame-ancestors)
  et [X-Frame-Options](/fr/docs/web-security/security-headers/x-frame-options),
  les pages de référence.
* [Comment poser frame-ancestors sans un header CSP complet](/fr/blog/frame-ancestors-without-csp-header),
  quand vous voulez la protection anti-clickjacking mais pas encore le reste
  d'une politique.
* [Quels headers de sécurité hérités retirer](/fr/blog/legacy-security-headers-to-retire),
  où `X-Frame-Options` se situe parmi les autres headers que les navigateurs ont
  dépassés.
* [Améliorer votre note de headers de sécurité](/fr/blog/improve-security-headers-grade),
  la checklist complète dont cette paire de headers fait partie.

## Sources [#sources]

* [CSP Level 3, relation entre frame-ancestors et X-Frame-Options](https://w3c.github.io/webappsec-csp/#frame-ancestors-and-frame-options)
* [CSP Level 3, la directive frame-ancestors](https://www.w3.org/TR/CSP3/#directive-frame-ancestors)
* [CSP Level 3, exclusions de la livraison via meta](https://www.w3.org/TR/CSP3/#meta-element)
* [RFC 7034, HTTP Header Field X-Frame-Options](https://datatracker.ietf.org/doc/html/rfc7034)
* [MDN, X-Frame-Options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Frame-Options)
* [MDN, CSP frame-ancestors](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/frame-ancestors)
* [MDN, notes de version de Firefox (retrait de ALLOW-FROM)](https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/70)
* [OWASP, Clickjacking Defense Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html)
* [Chromium, ancestor\_throttle.cc (gestion de X-Frame-Options et frame-ancestors)](https://github.com/chromium/chromium/blob/main/content/browser/renderer_host/ancestor_throttle.cc)
* [whatwg/html PR 10938 et w3c/webappsec-csp PR 702, les changements de formulation de 2025](https://github.com/whatwg/html/pull/10938)
