12k
All articles

Pourquoi rel="noopener" est devenu obsolète pour les liens

Pourquoi rel=noopener est devenu inutile pour les liens target=_blank, ce qu était le reverse tabnabbing, et quand noreferrer, opener ou COOP comptent encore.

OpenReplay Team
OpenReplay Team
Pourquoi rel="noopener" est devenu obsolète pour les liens

Pour un simple lien target="_blank", rel="noopener" est désormais redondant : toutes les versions actuelles de Chrome, Edge, Firefox et Safari appliquent automatiquement le comportement noopener, si bien qu’un target="_blank" seul définit déjà window.opener à null.

Si vous continuez à l’écrire par automatisme, ou si vous voyez votre linter signaler l’unique balise <a> que vous avez oubliée, vous colmatez une brèche que le navigateur a fermée il y a des années. Cet article explique la vulnérabilité que cet attribut devait prévenir, à quel moment les navigateurs ont fait de ce correctif le comportement par défaut, et les cas précis où rel reste réellement utile : noreferrer (non automatique), rel="opener" (pour réactiver le comportement) et l’en-tête Cross-Origin-Opener-Policy pour un contrôle à l’échelle du site.

Points clés à retenir

  • Sur les navigateurs modernes, un simple target="_blank" annule déjà window.opener : ajouter manuellement rel="noopener" relève donc de la défense en profondeur pour une faille que le navigateur a déjà refermée.
  • Le noopener implicite a été déployé par étapes (Safari en 2018-2019, Firefox 79 mi-2020, Chromium 88 début 2021) et fait désormais partie du standard HTML du WHATWG.
  • Le noopener implicite couvre environ 95 % de l’usage mondial des navigateurs, selon caniuse.com.
  • noreferrer n’est pas implicite : il supprime toujours l’en-tête Referer et implique également noopener. Ne l’ajoutez donc que si vous souhaitez protéger la confidentialité du référent.
  • Utilisez rel="opener" pour réactiver window.opener, et Cross-Origin-Opener-Policy: same-origin pour couper le partage de l’opener à l’échelle d’un document entier, en un seul endroit.

Le problème d’origine : le reverse tabnabbing

Avant que les navigateurs ne modifient leur comportement par défaut, un lien target="_blank" transmettait à la page nouvellement ouverte une référence active vers la page qui l’avait ouverte. Le reverse tabnabbing est l’attaque qui exploite ce mécanisme : la page de destination lit window.opener et redirige l’onglet d’origine vers un clone de phishing pendant que l’utilisateur a le focus sur le nouvel onglet. L’explication canonique du problème par Mathias Bynens le résume sans détour : partout où window.opener existe, la page ouverte peut rediriger l’ouvreur ailleurs, quelle que soit l’origine de l’une ou l’autre page.

L’exploit tient en une ligne exécutée dans le document ouvert :

if (window.opener) {
  window.opener.location = 'https://you-re-hacked.com';
}

Le détail crucial, c’est que cela fonctionne entre origines différentes. La lecture et l’écriture de window.opener.location ne sont pas bloquées lorsque les deux pages proviennent d’hôtes distincts : ni la politique de même origine (same-origin policy) ni CORS n’empêchent donc la redirection de l’ouvreur. Cela rendait la faille dangereuse partout où vous affichiez des liens générés par les utilisateurs ou provenant de tiers (forums, commentaires, champs de profil), là où un attaquant contrôle le href.

Ce qui a changé : target="_blank" implique désormais rel="noopener"

Les navigateurs ont corrigé le comportement par défaut. Sur les éléments <a>, <area> et <form>, un target="_blank" produit désormais le même effet que si vous écriviez rel="noopener" vous-même : le document ouvert reçoit null pour window.opener, sans qu’aucun attribut soit nécessaire. Ce comportement est inscrit dans la spécification HTML du WHATWG, dont les règles de suivi d’un hyperlien traitent toute cible _blank comme noopener, sauf si le lien s’y soustrait explicitement avec rel="opener". L’OWASP renvoie désormais ses lecteurs vers ce même comportement standardisé par défaut et considère l’attaque comme largement neutralisée sur les navigateurs à mise à jour continue.

Le changement s’est étalé sur environ trois ans : « les navigateurs modernes font cela » correspond donc à une chronologie, pas à une date unique.

MoteurPremière version stable avec noopener impliciteDate de diffusion approximative
Safari / WebKitSafari 12.1 (aperçu dans Tech Preview 68)Fin 2018 – 2019
Firefox / GeckoFirefox 79Mi-2020
Chromium (Chrome, Edge)Chrome/Edge 88Début 2021

Notez que ces versions décrivent le comportement implicite, et non le moment où l’attribut rel="noopener" lui-même a été pris en charge. Cette prise en charge remonte à plusieurs années auparavant et constitue un jalon distinct. Le tableau de caniuse sur le noopener implicite situe la prise en charge mondiale à environ 95 %, les navigateurs à mise à jour continue étant couverts depuis 2018 environ. La part restante est faible mais bien réelle : vérifiez donc vos propres statistiques d’audience avant de supprimer l’attribut. Le principal récalcitrant est l’ancien Edge non basé sur Chromium.

« Obsolète à écrire à la main » n’est pas synonyme d’« inutile »

Le fait que rel="noopener" soit redondant à saisir ne rend pas l’attribut rel inutile dans son ensemble. Le mot-clé désormais automatique est noopener, et lui seul. Les autres modifient toujours le comportement :

Mot-cléEffetFaut-il encore l’écrire en 2026 ?
noopenerMet window.opener à null dans la page ouverteNon, implicite avec target="_blank"
noreferrerSupprime l’en-tête Referer et implique noopenerUniquement si vous souhaitez la confidentialité du référent
openerRétablit window.opener (réactivation explicite)Oui, lorsque vous avez réellement besoin de la référence

noreferrer n’est pas implicite. Il supprime toujours l’en-tête Referer : ne l’ajoutez donc que si vous souhaitez effectivement dissimuler l’URL d’origine à la page de destination. Il apporte aussi le bénéfice de sécurité gratuitement : comme noreferrer annule également l’opener, ajouter noopener à ses côtés n’apporte rien. La combinaison courante rel="noopener noreferrer" est donc doublement redondante sur les navigateurs modernes, puisque noreferrer seul couvre les deux aspects.

Si vous avez réellement besoin que la page ouverte conserve sa référence window.opener (une popup qui renvoie un message, par exemple), activez-la explicitement avec rel="opener". Les notes de version de WebKit qui ont introduit ce changement le décrivent de la même façon : le comportement sécurisé est désormais celui par défaut, et rel="opener" est le moyen de l’inverser délibérément.

Une réserve honnête concernant la prise en charge des navigateurs anciens : ajouter rel="noopener" malgré tout est sans conséquence négative. La documentation de l’audit Lighthouse de Chrome souligne qu’expliciter l’attribut offre encore une protection pour quiconque est bloqué sur un moteur plus ancien tel qu’Edge Legacy. C’est du bruit sur les navigateurs modernes, mais ce n’est pas une erreur.

COOP : le contrôle scalable à l’échelle du site

Pour couper le partage de window.opener sur l’ensemble d’un document en un seul endroit, envoyez l’en-tête de réponse Cross-Origin-Opener-Policy: same-origin plutôt que d’annoter chaque lien. L’en-tête Cross-Origin-Opener-Policy (COOP) détermine si un document de premier niveau nouvellement ouvert rejoint votre groupe de contextes de navigation ou obtient le sien. Avec same-origin, les documents d’origine différente atterrissent dans un groupe séparé et les références entre eux et leur ouvreur sont coupées, ce qui ferme le canal de l’opener une fois pour toutes, de manière centralisée, plutôt que lien par lien.

# nginx
add_header Cross-Origin-Opener-Policy "same-origin";
// Express
app.use((req, res, next) => {
  res.set('Cross-Origin-Opener-Policy', 'same-origin');
  next();
});

Une contrainte : COOP ne peut être transmis que sous forme d’en-tête de réponse HTTP. Il n’existe pas d’équivalent <meta http-equiv> ; si votre infrastructure ne vous permet pas de définir des en-têtes de réponse, vous ne pouvez pas appliquer COOP. Il est largement pris en charge par les navigateurs actuels et mérite d’être activé au titre de la défense en profondeur. Le session replay d’un utilisateur réel cliquant sur un lien externe en target="_blank" est un moyen concret de confirmer que l’onglet d’origine n’a jamais été redirigé, et de reproduire tout signalement de navigation inattendue sur le navigateur exact utilisé par l’utilisateur.

Le verdict : que faire aujourd’hui

Pour du nouveau code ciblant les navigateurs modernes, n’ajoutez pas rel="noopener" à la main : le navigateur s’en charge pour vous. Vous pouvez sans risque assouplir les règles de linting qui l’imposent sur chaque target="_blank", comme react/jsx-no-target-blank ; ne gardez la règle activée que si vous devez couvrir Edge Legacy ou d’autres moteurs antérieurs à 2021. Ajoutez rel="noreferrer" quand — et uniquement quand — vous voulez supprimer l’en-tête Referer. Utilisez rel="opener" dans les rares cas où vous avez besoin de récupérer la référence à l’ouvreur. Pour une garantie scalable à l’échelle du document, envoyez Cross-Origin-Opener-Policy: same-origin.

À signaler : les recommandations antérieures, y compris l’ancien article d’OpenReplay préconisant rel="noreferrer noopener" sur chaque lien, présentent noopener comme un attribut à écrire systématiquement et ne tiennent pas compte du comportement implicite par défaut. Cela reflète une habitude que le secteur a conservée longtemps après l’évolution des navigateurs. La position exacte en 2026 est plus nuancée : noopener est désormais le comportement par défaut, l’ajouter à la main est donc obsolète, tandis que noreferrer, rel="opener" et COOP remplissent chacun un rôle distinct. Utilisez-les à bon escient et laissez le navigateur s’occuper du reste.

FAQ

Est-ce que rel='noreferrer' inclut rel='noopener' ?

Oui. Définir rel='noreferrer' implique automatiquement rel='noopener' : cela met donc window.opener à null en plus de supprimer l'en-tête Referer. La combinaison courante rel='noopener noreferrer' est donc doublement redondante sur les navigateurs modernes, car noreferrer seul couvre à la fois l'annulation de l'opener et la suppression du référent. N'ajoutez noreferrer que si vous souhaitez réellement dissimuler l'URL d'origine à la page de destination.

Que se passe-t-il si j'omets complètement rel='noopener' sur un lien target='_blank' aujourd'hui ?

Rien de dangereux sur les navigateurs modernes. Un simple target='_blank' met déjà window.opener à null, car Chrome, Edge, Firefox et Safari appliquent implicitement le comportement noopener, une règle codifiée dans le standard HTML du WHATWG. Caniuse estime cette couverture à environ 95 % de l'usage mondial des navigateurs. Le reverse tabnabbing est neutralisé par défaut ; la seule brèche concerne les moteurs anciens comme Edge Legacy, non basé sur Chromium.

Puis-je définir Cross-Origin-Opener-Policy avec une balise meta plutôt qu'un en-tête ?

Non. COOP ne peut être transmis que sous forme d'en-tête de réponse HTTP, et il n'existe pas d'équivalent meta http-equiv. Si votre infrastructure ne permet pas de définir des en-têtes de réponse, vous ne pouvez pas appliquer COOP et devez vous rabattre sur les attributs rel par lien ou sur le comportement noopener implicite par défaut. Lorsque vous pouvez définir des en-têtes, l'envoi de Cross-Origin-Opener-Policy: same-origin coupe le partage de window.opener pour l'ensemble d'un document, en un point central, plutôt que d'annoter chaque lien.

Comment réactiver window.opener lorsque j'en ai réellement besoin ?

Utilisez explicitement rel='opener' sur le lien. Puisque le comportement sécurisé consistant à mettre window.opener à null est désormais celui par défaut dans les navigateurs, rel='opener' est le moyen de rétablir délibérément la référence à l'ouvreur, par exemple lorsqu'une popup doit renvoyer un message à la page qui l'a ouverte. Cela inverse le comportement noopener implicite pour ce lien précis, sans affecter les autres.

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — self-hosted, with full data ownership.

Star on GitHub

We use cookies to improve your experience. By using our site, you accept cookies.