Aussi disponible en : English · Español · Português · العربية
Attribut sandbox d’iframe : le construire et lire ce qu’il fait vraiment
Les treize jetons, les quatre règles pour les combiner et la condition que tout le monde retire du fameux avertissement.
Qu’est-ce que l’attribut sandbox d’un iframe ?
L’attribut sandbox soumet le contenu d’un iframe à une série de restrictions supplémentaires. Écrivez-le sans valeur et la page encadrée reçoit le traitement le plus strict qui soit : les scripts ne s’exécutent pas, les formulaires ne partent pas, les fenêtres surgissantes et les boîtes de dialogue sont bloquées, et le contenu est traité comme venant d’une origine opaque unique, donc il n’atteint rien de chez vous. Chaque jeton ajouté rend l’une de ces capacités.
Il y a exactement treize jetons, et la norme HTML les énumère en une seule phrase. Cela compte plus qu’il n’y paraît : les navigateurs ignorent les valeurs d’attribut qu’ils ne reconnaissent pas, si bien qu’une invention plausible n’accorde rien et ne signale rien. La valeur est de plus un ensemble non ordonné de jetons uniques, insensible à la casse ASCII : l’ordre n’importe jamais, ALLOW-SCRIPTS vaut allow-scripts, et écrire un jeton deux fois n’est pas conforme même si cela ne change rien.
Ce constructeur coche les jetons, écrit l’attribut, puis vous relit la combinaison — c’est précisément la partie que les listes de cases à cocher laissent de côté, parce que plusieurs des règles portent sur des jetons qui interagissent et non sur des jetons isolés.
Comment l’utiliser
- Cochez les capacités dont le contenu a réellement besoin. Chaque jeton porte une ligne expliquant ce qu’il réactive et, une fois la page chargée, une note indiquant si votre navigateur le reconnaît. Les boutons d’exemple chargent cinq cas réels, dont l’exemple de la norme elle-même.
- Indiquez d’où vient la page encadrée. Même origine, origine différente, ou vous ne pouvez rien promettre. C’est la question qui décide si le fameux avertissement sur allow-scripts et allow-same-origin vous concerne, et la seule chose qu’un validateur ne peut pas savoir.
- Lisez les constats, puis copiez la balise. Les constats sont de quatre sortes : du balisage non conforme, une sortie du bac à sable, des jetons sans effet dans cette combinaison, et de simples remarques. Si votre iframe se trouve dans un autre iframe sandboxé, collez l’attribut de celui-ci dans la zone d’imbrication pour voir ce qui survit.
L’avertissement que tout le monde répète, et la clause qu’on retire
Le conseil que vous avez entendu est : ne mettez jamais allow-scripts et allow-same-origin ensemble. Ce que dit la norme, c’est que mettre les deux « lorsque la page incorporée a la même origine que la page contenant l’iframe permet à la page incorporée de simplement supprimer l’attribut sandbox puis de se recharger, sortant ainsi complètement du bac à sable ».
C’est la clause du milieu qui porte tout. L’évasion n’a rien de magique : un script de même origine à l’intérieur du cadre atteint le document qui le contient, supprime l’attribut et recharge. Une page d’une autre origine ne touche pas ce document, elle n’a donc aucun moyen d’exécuter le tour. L’exemple de la norme elle-même est un iframe dont le sandbox vaut allow-same-origin, allow-forms et allow-scripts autour d’une carte tierce, et elle qualifie ce bac à sable d’« encore utile » puisque les fenêtres surgissantes et les plugins restent bloqués.
La règle honnête est donc plus étroite et plus utile que la version populaire : la paire est une porte de sortie quand vous encadrez quelque chose que vous servez vous-même, et une configuration raisonnable quand vous encadrez l’origine d’autrui. Si vous ne pouvez pas garantir laquelle des deux — une redirection peut amener une URL d’une autre origine sur la vôtre — mieux vaut supposer l’évasion disponible, ce qui est exactement pourquoi le validateur du W3C signale la paire sans condition. C’est un défaut sensé, non une affirmation sur votre cas.
Les règles qu’une liste de cases ne vous dira pas
Deux combinaisons ne sont pas du balisage conforme. allow-top-navigation et allow-top-navigation-by-user-activation ne doivent pas être spécifiés ensemble, car c’est redondant : seul l’inconditionnel a un effet. Et allow-top-navigation-to-custom-protocols ne doit pas être spécifié à côté d’allow-top-navigation ni d’allow-popups, pour la même raison. En envoyant les deux cas au validateur Nu du W3C, le premier revient en erreur et il ne dit strictement rien du second, dans aucune de ses deux écritures : l’une des deux règles n’est donc pas appliquée par l’outil avec lequel la plupart des gens vérifieraient.
Deux jetons peuvent aussi être totalement inertes. allow-modals ne fait rien seul : la norme dit qu’alert, confirm et prompt réclament allow-modals et allow-same-origin, et que l’URL chargée doit être de même origine que la page de premier niveau. allow-popups-to-escape-sandbox régit ce dont hérite une fenêtre ouverte par le contenu, donc sans allow-popups il n’y a aucune fenêtre à régir. Ni l’un ni l’autre n’est une erreur, donc aucun validateur ne les mentionne : vous vous retrouvez simplement avec un jeton qui a l’air de servir à quelque chose.
L’imbrication ne fait que resserrer. La norme travaille un exemple où une page en encadre une autre avec allow-same-origin et allow-forms, laquelle en encadre une troisième avec allow-scripts : la plus interne ne reçoit rien, car « l’iframe dans A a les scripts désactivés, et cela l’emporte sur le mot-clé allow-scripts posé sur l’iframe dans B ». Un cadre intérieur peut restreindre ce qu’on lui a donné ; il ne peut jamais rendre ce qu’un cadre extérieur a retiré.
Enfin, les drapeaux se figent à la navigation. « Ces drapeaux ne prennent effet que lorsque le content navigable de l’élément iframe est navigué. Les retirer, ou retirer l’attribut sandbox entier, n’a aucun effet sur une page déjà chargée. » Modifier l’attribut par script ne fait rien tant que rien ne recharge, et c’est pourquoi la norme déconseille de le faire.
Limites assumées
Cet outil lit un attribut ; il n’audite pas une page. Il ne voit pas votre Content-Security-Policy, qui peut imposer son propre bac à sable via la directive sandbox, ni l’attribut allow, qui est un mécanisme distinct portant sur des permissions plutôt que sur des restrictions. Il vous croit également sur parole quant à l’origine de la page encadrée, parce que c’est le seul moyen de la connaître à l’avance.
La note de prise en charge par jeton vient d’une question posée à votre navigateur. La norme définit les jetons pris en charge par cet attribut comme les valeurs autorisées « et prises en charge par l’agent utilisateur », ce qui rend la question répondable — mais elle indique ce que le navigateur analysera, non ce qu’il honorera, et un moteur très ancien qui n’expose aucune liste de jetons pris en charge ne répond tout simplement pas.
Une chose mérite d’être dite sans détour : un bac à sable ne remplace pas le fait de ne pas servir de contenu hostile depuis votre propre origine. La norme le dit dans la même section, et la raison en est qu’un attaquant capable de faire ouvrir directement l’URL encadrée l’obtient hors bac à sable, dans votre origine, sans le moindre iframe.
Pourquoi est-ce gratuit ?
Ce sont treize chaînes de caractères et une poignée de règles, et votre navigateur fait le tout pendant que vous cochez des cases. Aucun serveur n’intervient : il n’y a donc rien à facturer ni de compte à créer.
Rien n’est envoyé. L’attribut que vous construisez reste dans cet onglet.