Protection anti-clickjacking quand vous ne pouvez pas poser de header CSP
CentralCSP Team ·
Dernière mise à jour:
La protection anti-clickjacking a besoin d'un vrai header de réponse HTTP. La directive de la politique de sécurité du contenu (CSP) qui contrôle qui peut placer votre page dans une frame, frame-ancestors, est silencieusement ignorée quand la politique provient d'une balise <meta>, si bien qu'une CSP livrée en meta ne vous donne aucune protection contre le framing. Si vous ne pouvez pas poser librement vos headers, le repli limité par l'hébergeur est X-Frame-Options, plus simple et plus contraint. Cet article explique la faille de la balise meta, ce que X-Frame-Options peut et ne peut pas faire, et vers quoi vous tourner quand vos seules options sont des headers limités ou une balise meta.
frame-ancestors est ignoré dans une balise meta
frame-ancestors décide quelles origines peuvent embarquer votre page dans une frame, ce qui est votre défense contre le clickjacking (un attaquant qui embarque votre page de façon invisible et pousse un utilisateur à cliquer dessus sans le savoir). Cela fonctionne quand la politique arrive via le header de réponse Content-Security-Policy. Cela ne fonctionne pas depuis une balise meta.
La spécification CSP liste frame-ancestors parmi les directives ignorées quand la politique est livrée dans un élément <meta http-equiv>. Le navigateur conserve le reste de la politique meta et écarte discrètement cette directive. Aucune erreur de console ne vous indique que la page est sans protection, et c'est ce qui rend la chose dangereuse : la politique semble présente, mais la règle de framing a disparu.
<!-- frame-ancestors here is silently ignored, no clickjacking protection -->
<meta http-equiv="Content-Security-Policy" content="frame-ancestors 'none'">C'est l'une des rares directives qui ne fonctionnent qu'en header. La liste complète et le raisonnement sont dans balise meta CSP contre header HTTP. Pour le clickjacking, la conclusion est simple et sans appel : si vous ne pouvez émettre qu'une balise meta, vous ne pouvez pas utiliser frame-ancestors, et il vous faut un mécanisme différent.
X-Frame-Options, le repli limité par l'hébergeur
Quand vous ne pouvez pas poser de header CSP mais pouvez poser certains headers de réponse, X-Frame-Options est l'ancien header qui contrôle le framing. Certains hébergeurs et CDN exposent une courte liste de headers de sécurité autorisés même quand ils ne vous laissent pas définir une CSP arbitraire, et X-Frame-Options figure souvent sur cette liste. Il a deux valeurs utilisables :
X-Frame-Options: DENYX-Frame-Options: SAMEORIGINDENY empêche tout site, y compris le vôtre, de placer la page dans une frame. SAMEORIGIN n'autorise que votre propre origine à la framer. C'est tout son vocabulaire. Le header est grossier à dessein, ce qui est à la fois sa limite et la raison pour laquelle il fonctionne encore comme repli.
Les contraintes comptent :
- Pas d'allowlist de plusieurs origines.
frame-ancestorspeut nommer plusieurs embarqueurs de confiance (frame-ancestors 'self' https://partner.example).X-Frame-Optionsne le peut pas. C'est la même origine ou personne, sans aucun moyen d'autoriser un partenaire nommé. ALLOW-FROMest déprécié et ne fonctionne pas. L'ancienne valeurX-Frame-Options: ALLOW-FROM https://partner.exampleétait censée autoriser un seul embarqueur externe. Les navigateurs modernes l'ignorent. Ne comptez pas dessus ; si vous devez autoriser un partenaire précis à vous framer, il vous fautframe-ancestors, donc un vrai header.frame-ancestorsle supplante. Quand une page envoie les deux, les navigateurs honorent la directive CSP et ignorentX-Frame-Options(voyez X-Frame-Options contre frame-ancestors pour la comparaison complète).X-Frame-Optionsest donc le repli que vous utilisez uniquement quandframe-ancestorsne vous est pas accessible.
Pour le comportement détaillé de la directive, sa syntaxe et son articulation avec le header hérité, voyez la référence de la directive frame-ancestors. Cet article est la version pratique « que faire quand je ne peux pas poser le header » ; la référence est la version complète.
Que faire avec des headers limités ou seulement une balise meta
Adaptez le correctif à ce que votre hébergeur vous laisse réellement contrôler.
Vous pouvez poser des headers de réponse arbitraires. Utilisez frame-ancestors sur un vrai header Content-Security-Policy et laissez tomber X-Frame-Options entièrement. frame-ancestors 'none' pour bloquer tout framing, frame-ancestors 'self' pour la même origine seulement, ou une allowlist nommée pour des partenaires précis. C'est l'option moderne et expressive, à privilégier dès qu'elle est disponible.
Content-Security-Policy: frame-ancestors 'self' https://partner.exampleVous ne pouvez poser qu'une courte liste de headers de sécurité (pas de CSP). Utilisez X-Frame-Options: DENY si rien ne doit framer la page, ou SAMEORIGIN si vos propres pages la frament. Vous devrez accepter de ne pas pouvoir autoriser ici un partenaire externe nommé. Si un partenaire a réellement besoin de vous embarquer, il vous faudra trouver un moyen de poser un header CSP, il n'existe pas de raccourci limité aux headers pour cela.
Vous ne pouvez émettre qu'une balise meta. Vous n'avez aucune protection anti-clickjacking depuis la CSP, car frame-ancestors est ignoré dans une balise meta et X-Frame-Options ne peut pas se définir depuis le markup (c'est un header de réponse sans équivalent en balise meta). Le markup seul ne peut tout simplement pas protéger contre le framing. Voyez-y une raison de faire configurer ne serait-ce qu'un seul vrai header de sécurité, via la plateforme, un reverse proxy, un edge worker ou un autre hébergeur, plutôt qu'un problème qu'une balise <meta> viendrait masquer.
X-Frame-Options est un header hérité, et une fois que vous avez une CSP avec frame-ancestors, il est redondant. C'est l'un des headers à retirer à ce moment-là, traité dans les headers de sécurité hérités à retirer. Ne le gardez que comme repli tant que vous ne pouvez pas poser de CSP.
Vérifiez ce que vous avez réellement déployé
Comme l'échec de la balise meta est silencieux, contrôlez la réponse que votre serveur envoie vraiment plutôt que de vous fier au markup. Le scanner de headers de sécurité gratuit lit les headers de réponse déployés et montre si frame-ancestors (dans la CSP) ou X-Frame-Options est présent et quelle valeur il porte, de quoi confirmer que la page n'est pas framable quand elle ne doit pas l'être.
Si la protection anti-clickjacking s'inscrit dans un besoin plus large de surveiller ce que vos pages envoient et chargent dans le temps, la suite CSP CentralCSP surveille votre CSP et les scripts de chaque page à partir du trafic réel, pas seulement d'un scan ponctuel. Vous pouvez démarrer un essai gratuit pour voir les rapports et l'état des headers sur tout votre site.
Sources
- MDN, X-Frame-Options
- MDN, CSP frame-ancestors
- W3C, Content Security Policy Level 3
- OWASP, Clickjacking Defense Cheat Sheet