Dans cet article, nous verrons comment intégrer une page web dans une autre, tout en minimisant les risques encourus par une telle manipulation.
Prérequis : | Vous devriez au préalable savoir comment créer un document HTML simple. |
---|---|
Objectifs : | Connaître les risques encourus lorsqu'on imbrique des pages web entre elles et savoir comment intégrer une page web au sein d'une autre page tout en minimisant ces risques. |
L'imbrication des pages, quelques mots d'histoire
Imbriquer des pages entre elles peut sembler étrange voire contre-nature mais cela existe depuis les débuts du Web. Lorsque la bande passante était utilisée par des modems 56k (voire moindre), pour réduire le temps de téléchargement, les pages web étaient fragmentées en morceaux appelés frames, tous intégrées dans un frameset. Malheureusement, les frames ont apporté plus de problèmes que de solutions et le concept de frame/frameset a disparu depuis l'apparition d'AJAX.
Cela dit, il existe des cas où imbriquer des pages web est une solution valide. C'est notamment le cas lorsqu'on veut inclure du contenu généré par un utilisateur ou du contenu tiers (des publicités par exemple). Afin d'améliorer la sécurité lors de telles opérations, il est possible d'intégrer le contenu dans une iframe HTML5. Dans certains cas complexes, cela peut également permettre au navigateur d'être plus rapide car les arbres DOM à traiter peuvent être plus légers.
Malgré tout, l'imbrication de pages web a des conséquences significatives sur la sécurité, la performance et l'accessibilité. Avant de la mettre en œuvre, assurez-vous d'en comprendre les enjeux et les risques afin de servir au mieux vos visiteurs.
Une imbrication simple
La plupart du temps, vous aurez besoin d'une <iframe>
pour imbriquer des pages web entre elles. Pour commencer, voici quelques questions :
- Quel est le document que j'intègre dans la page web ? L'URL du document sera la valeur de l'attribut
src
. - Quel espace doit occuper le document par rapport à la page web « parente » ? Pour cette information, on utilisera les attributs
width
etheight
. - Que se passe-t-il lorsque l'agent utilisateur ne supporte pas les iframes ? Dans ces cas, il faut fournir un contenu HTML à utiliser en recours (ça peut, par exemple, être un lien vers le document qui aurait dû être imbriqué), ce contenu sera placé entre les balises
<iframe>
. - Il ne faut pas oublier l'attribut
sandbox
, hautement conseillé, qui permet de renforcer la sécurité des requêtes effectuées.
Au final, le code ressemblera à :
<iframe src="https://developer.mozilla.org/fr/docs/Web/JavaScript/" width="100%" height="500" sandbox> <p> <a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/"> Un lien à utiliser dans les cas où les navigateurs ne supportent pas les <i>iframes</i>. </a> </p> </iframe>
Afin d'améliorer la vitesse de chargement du site principal, il peut être utile de définir l'attribut src
de l'iframe grâce à JavaScript, une fois que le contenu principal a été chargé. De cette façon, votre page sera utilisable plus tôt et le temps de chargement « officiel » de votre page sera réduit (ce qui peut être une métrique importante pour le référencement).
Si vous n'appréciez pas la bordure épaisse autour de l'<iframe>
, vous pouvez utiliser border
: none;
dans votre code CSS.
Soyez couverts
Dans les paragraphes précédents, nous avions insisté sur les aspects liés à la sécurité. Nous y voilà revenus. Les développeurs de navigateurs et les développeurs web ont appris à leurs dépens que les iframes pouvaient être un vecteur d'attaque visant à modifier une page web ou à faire faire aux visiteurs quelque chose à leur insu.
Clickjacking est l'une des attaques connues utilisant les iframes : un attaquant placera une iframe invisible dans le document pour capturer les interactions entre l'utilisateur et le site web. Cela permet de détourner les utilisateurs ou de subtiliser des données sensibles.
Voici quelques mesures à prendre pour mieux protéger votre site, de la plus simple à la plus complexe.
Ne pas intégrer de contenu tiers
Il peut arriver que vous n'ayez pas le choix, en revanche si vous l'avez, ne pas intégrer de contenu tiers pourra certainement vous épargner des maux de tête. Si vous avez développé le contenu intégré, regardez-y à deux fois. Si le contenu provient de l'extérieur, considérez-le comme dangereux.
Un autre aspect que celui de la sécurité intervient ici : la propriété intellectuelle. La plupart des contenus, qu'ils soient en ligne ou non, sont placés sous le droit d'auteur, y compris du contenu dont on penserait qu'il est libre de droit (par exemple, la plupart des images sur Wikimedia Commons). N'affichez jamais du contenu sur votre page web si ce n'est pas le vôtre et que vous n'avez pas eu l'accord expresse de l'auteur. Les peines infligées pour infraction au droit d'auteur peuvent être importantes. Là encore, on n'est jamais trop prudent.
Si le contenu est placé sous licence, vous devez respecter les termes de la licence. Par exemple, MDN est sous licence CC-BY-SA. Cela signifie que vous devez créditer les auteurs correctement lorsque vous citez le contenu d'une de ses pages, même si vous y apportez des modifications.
Utiliser HTTPS
HTTPS est la version chiffrée de HTTP. Vous devriez utiliser HTTPS dès que possible :
- HTTPS réduit les chances que le contenu distant soit modifié lors du transport ;
- HTTPS empêche le contenu intégré d'accéder au contenu du document parent, et vice versa.
Les certificats de sécurité ne sont pas donnés et si vous ne pouvez pas vous en procurer un, vous devrez servir votre document parent avec HTTP. Cependant, suite à ce qui a été vu avant, dans aucun cas vous ne devez intégrer du contenu tiers qui soit transporté par HTTP (dans le meilleur des cas, cela se traduira, pour l'utilisateur, par un avertissement dans le navigateur).
Utiliser l'attribut sandbox
, toujours
Si vous souhaitez minimiser les risques, ne donnez que les permissions indispensables nécessaires. Bien entendu, cela s'applique également à votre contenu.
Le contenu qui n'est pas mis dans un bac à sable (sandbox) a trop de droits par défaut (utilisations de scripts, de formulaires, de pop-ups, etc). Tant que c'est possible, imposez toutes les restrictions en utilisant sandbox
sans paramètres.
Si c'est nécessaire, vous pouvez ajouter certaines permissions, une à une, dans la valeur de sandbox
. Attention ! Il ne faut jamais ajouter allow-scripts
et allow-same-origin
en même temps car le contenu placé en bac à sable pourrait alors désactiver les protections.
La mise en bac à sable (sandboxing) n'offre aucune protection si l'attaquant peut détourner les visiteurs et leur faire visiter un contenu dangereux directement (qui n'est pas dans une iframe
). S'il y a une probabilité qu'un contenu soit dangereux (par exemple : un contenu généré par un utilisateur), faites en sorte que ce contenu soit servir avec une origine différente de celle du site principal.
Établir des canaux de communication entre les contenus
Dans certains cas, il peut être utile de faire communiquer une iframe avec le document hôte. Mettre en place de tels canaux de communication est assez simple avec JavaScript. Si l'iframe est correctement mise en bac à sable, ni l'iframe ni le document parent ne pourront accéder au DOM de l'autre (sans bac à sable, ça serait possible et incroyablement dangereux). Pour échanger de tels messages, l'API postMessage
est la seule méthode sécurisée.
Configurer les directives CSP
CSP fournit un ensemble d'en-têtes HTTP conçus pour améliorer la sécurité d'un document HTML. Lorsqu'on utilise des iframe, il faut s'assurer de configurer son serveur pour envoyer un en-tête X-Frame-Options
approprié. Cela peut empêcher d'autres sites web d'intégrer le contenu de votre page dans d'autres pages web (ce qui serait une première étape pour faire du clickjacking ou effectuer d'autres attaques). Pour plus d'informations sur ce sujet, le billet de Frederik Braun (en anglais) est particulièrement intéressant.
Placez le code HTML dans un bac à sable (sandboxing)
Nous avons déjà évoqué la mise en bac à sable pour les contenus embarqués mais cela peut également concerner votre propre contenu. Il est parfois avantageux d'aller encore plus loin en découpant sa page web en plusieurs iframes, chacune mise dans un bac à sable, en gérant un minimum de privilèges et en les coordinant depuis le document principal (Mike West décrit ce sujet en détails et explique comment la séparation des privilèges permet d'améliorer le niveau de sécurité). Découpage une page de cette façon peut également permettre d'obtenir de meilleures performances car les arbres DOM manipulés sont plus légers.
En utilisant les deux nouveaux attributs d'iframe
: seamless
et srcdoc
, vous pouvez intégrer des fragments de code HTML dans un document HTML. Pour supporter les navigateurs historiques, il est possible de fournir un contenu alternatif via une URL avec src
(cela peut être une URI de données). Voici un exemple simple :
<iframe sandbox seamless src="fallback.html" srcdoc=" <p> Ce paragraphe est dans un bac à sable. </p> "> Du contenu pour les navigateurs qui ne supportent pas les iframes. </iframe>
Pour l'attribut srcdoc
, les quotes doivent être échappées ("
) et les ampersandes doivent être doublement échappées (&amp;
pour représenter une ampersande simple (&)).