Por que rel='noopener' Está Obsoleto para Links
Por que rel=noopener ficou obsoleto em links target=_blank, o que era o reverse tabnabbing e quando noreferrer, opener ou COOP ainda importam.
Para um link target="_blank" simples, rel="noopener" agora é redundante: todas as versões atuais de Chrome, Edge, Firefox e Safari aplicam o comportamento de noopener automaticamente, então um target="_blank" isolado já define window.opener como null.
Se você ainda digita isso por memória muscular, ou vê o linter sinalizar aquela única âncora que você esqueceu, está remendando um buraco que o navegador fechou anos atrás. Este artigo explica a vulnerabilidade que ele pretendia prevenir, quando os navegadores tornaram a correção padrão, e os casos precisos em que rel ainda faz trabalho real: noreferrer (não automático), rel="opener" (para voltar a habilitar) e o header Cross-Origin-Opener-Policy para controle em todo o site.
Principais Conclusões
- Em navegadores modernos, um
target="_blank"isolado já anulawindow.opener, então adicionarrel="noopener"manualmente é defesa em profundidade para um buraco que o navegador já fechou. - O
noopenerimplícito chegou em etapas (Safari em 2018–19, Firefox 79 em meados de 2020, Chromium 88 no início de 2021) e agora faz parte do padrão HTML da WHATWG. - O
noopenerimplícito cobre aproximadamente 95% do uso global de navegadores, segundo o caniuse.com. noreferrernão é implícito: ele ainda remove o headerReferere também implicanoopener, então adicione-o apenas quando quiser privacidade de referrer.- Use
rel="opener"para voltar a habilitarwindow.opener, eCross-Origin-Opener-Policy: same-originpara cortar o compartilhamento de opener em todo um documento em um único lugar.
O problema original: reverse tabnabbing
Antes de os navegadores mudarem o padrão, um link target="_blank" entregava à página recém-aberta uma referência ativa de volta para a página que a abriu. Reverse tabnabbing é o ataque que explora isso: a página de destino lê window.opener e redireciona a aba original para um clone de phishing enquanto o usuário está focado na nova aba. A explicação canônica de Mathias Bynens sobre o problema resume tudo de forma direta: onde quer que window.opener exista, a página aberta pode direcionar a página que a abriu para outro lugar, qualquer que seja a origem à qual cada página pertença.
O exploit é uma única linha executada no documento aberto:
if (window.opener) {
window.opener.location = 'https://you-re-hacked.com';
}
O detalhe crítico é que isso funciona entre origens diferentes. Ler e escrever window.opener.location não é bloqueado quando as duas páginas vêm de hosts diferentes, então nem a same-origin policy nem o CORS impedem o redirecionamento da página que abriu. Isso tornava a situação perigosa em qualquer lugar onde você renderizasse links gerados por usuários ou de terceiros (fóruns, comentários, campos de perfil) em que um atacante controla o href.
O que mudou: target=“_blank” agora implica rel=“noopener”
Discover how at OpenReplay.com.
Os navegadores corrigiram o padrão. Em elementos <a>, <area> e <form>, um target="_blank" agora carrega o mesmo efeito de escrever rel="noopener" você mesmo: o documento aberto recebe null de window.opener, sem necessidade de atributo. Esse comportamento está escrito na especificação HTML da WHATWG, cujas regras para seguir um hyperlink tratam qualquer target _blank como noopener, a menos que o link opte por sair disso com rel="opener". A OWASP agora aponta os leitores para esse mesmo padrão padronizado e trata o ataque como largamente encerrado em navegadores evergreen.
A mudança foi implantada ao longo de cerca de três anos, então “navegadores modernos fazem isso” é uma linha do tempo, não uma data única:
| Engine | Primeira versão estável com noopener implícito | Data aproximada de lançamento |
|---|---|---|
| Safari / WebKit | Safari 12.1 (preview no Tech Preview 68) | Final de 2018 – 2019 |
| Firefox / Gecko | Firefox 79 | Meados de 2020 |
| Chromium (Chrome, Edge) | Chrome/Edge 88 | Início de 2021 |
Observe que essas versões descrevem o comportamento implícito, não quando o atributo rel="noopener" em si passou a ser suportado. Isso aconteceu anos antes e é um marco diferente. A tabela de noopener implícito do Caniuse coloca o suporte global em cerca de 95%, com navegadores evergreen cobertos desde por volta de 2018. A fatia restante é pequena, mas real, então verifique suas próprias analytics antes de remover o atributo. O caso remanescente notável é o Edge legado (não-Chromium).
Obsoleto para adicionar manualmente não é o mesmo que inútil
O fato de rel="noopener" ser redundante de digitar não torna todo o atributo rel inútil. A keyword que agora é automática é especificamente noopener. As outras ainda alteram o comportamento:
| Keyword | O que faz | Ainda precisa ser digitada em 2026? |
|---|---|---|
noopener | Anula window.opener na página aberta | Não, é implícito com target="_blank" |
noreferrer | Remove o header Referer e implica noopener | Apenas quando você quer privacidade de referrer |
opener | Restaura window.opener (volta a habilitar) | Sim, quando você genuinamente precisa da referência |
noreferrer não é implícito. Ele ainda suprime o header Referer, então adicione-o apenas quando você realmente quiser ocultar a URL de origem do destino. Ele também traz o benefício de segurança de graça: como noreferrer também anula o opener, adicionar noopener junto não acrescenta nada. Isso torna a combinação comum rel="noopener noreferrer" duplamente redundante em navegadores modernos, já que noreferrer por si só cobre as duas preocupações.
Se você genuinamente precisa que a página aberta mantenha sua referência window.opener (um popup que envia uma mensagem de volta, por exemplo), habilite explicitamente com rel="opener". As release notes do WebKit que introduziram a mudança descrevem isso da mesma forma: o comportamento seguro agora é o padrão, e rel="opener" é como você o reverte deliberadamente.
Uma ressalva honesta sobre suporte legado: adicionar rel="noopener" de qualquer forma é inofensivo. A documentação da auditoria Lighthouse do Chrome observa que escrever o atributo explicitamente ainda oferece alguma cobertura para quem está preso a uma engine mais antiga, como o Edge Legacy. É ruído em navegadores modernos, mas não está errado.
COOP: o controle escalável, em todo o site
Para cortar o compartilhamento de window.opener em um documento inteiro de uma só vez, envie o header de resposta Cross-Origin-Opener-Policy: same-origin em vez de decorar cada link. O header Cross-Origin-Opener-Policy (COOP) decide se um documento de nível superior recém-aberto entra no seu browsing context group ou recebe um próprio. Sob same-origin, documentos cross-origin ficam em um grupo separado e as referências entre eles e a página que os abriu são cortadas, o que fecha o canal do opener uma única vez, de forma centralizada, em vez de âncora por âncora.
# nginx
add_header Cross-Origin-Opener-Policy "same-origin";
// Express
app.use((req, res, next) => {
res.set('Cross-Origin-Opener-Policy', 'same-origin');
next();
});
Uma restrição: o COOP é entregue apenas como header de resposta HTTP. Não existe equivalente em <meta http-equiv>, então se você não pode definir headers de resposta na sua infraestrutura, não pode aplicar o COOP. Ele é amplamente suportado nos navegadores atuais e vale a pena ativá-lo como defesa em profundidade. Um session replay de um usuário real clicando em um link externo com target="_blank" é uma forma prática de confirmar que a aba original nunca foi navegada, e de reproduzir qualquer relato de navegação inesperada exatamente no navegador que o usuário estava usando.
O veredito: o que fazer agora
Para código novo voltado a navegadores modernos, não adicione rel="noopener" manualmente; o navegador define isso para você. Você pode relaxar com segurança as regras de lint que o forçam em todo target="_blank", como react/jsx-no-target-blank; mantenha a regra ativada apenas se precisar cobrir o Edge Legacy ou outras engines anteriores a 2021. Adicione rel="noreferrer" quando, e somente quando, quiser suprimir o header Referer. Use rel="opener" no caso raro em que precisa da referência ao opener de volta. Para uma garantia escalável em todo o documento, envie Cross-Origin-Opener-Policy: same-origin.
Vale destacar: orientações anteriores, incluindo o próprio post mais antigo da OpenReplay recomendando rel="noreferrer noopener" em todo link, tratam noopener como algo que você deve sempre digitar e não levam em conta o padrão implícito. Isso reflete um hábito ao qual a indústria se apegou muito depois de os navegadores terem mudado. A posição correta em 2026 é mais restrita: noopener agora é o padrão, então adicioná-lo manualmente é obsoleto, enquanto noreferrer, rel="opener" e o COOP cada um ainda cumpre um papel distinto. Recorra a esses de forma deliberada, e deixe o navegador cuidar do resto.
Perguntas Frequentes
rel='noreferrer' inclui rel='noopener'?
Sim. Definir rel='noreferrer' implica rel='noopener' automaticamente, então ele anula window.opener além de remover o header Referer. Isso significa que a combinação comum rel='noopener noreferrer' é duplamente redundante em navegadores modernos: noreferrer sozinho cobre tanto a anulação do opener quanto a supressão do referrer. Adicione noreferrer apenas quando realmente quiser ocultar a URL de origem da página de destino.
O que acontece se eu omitir completamente rel='noopener' em um link target='_blank' hoje?
Nada perigoso em navegadores modernos. Um target='_blank' isolado já define window.opener como null porque Chrome, Edge, Firefox e Safari aplicam o comportamento de noopener implicitamente, uma regra codificada no padrão HTML da WHATWG. O Caniuse coloca isso em cerca de 95% do uso global de navegadores. O reverse tabnabbing é inerte por padrão; a única lacuna são engines legadas como o Edge Legacy não-Chromium.
Posso definir Cross-Origin-Opener-Policy usando uma meta tag em vez de um header?
Não. O COOP é entregue apenas como header de resposta HTTP, e não existe equivalente em meta http-equiv. Se sua infraestrutura não pode definir headers de resposta, você não pode aplicar o COOP e precisa recorrer aos atributos rel por link ou ao padrão implícito de noopener. Quando você pode definir headers, enviar Cross-Origin-Opener-Policy: same-origin corta o compartilhamento de window.opener em um documento inteiro, em um único lugar central, em vez de decorar cada âncora.
Como volto a habilitar window.opener quando realmente preciso dele?
Use rel='opener' explicitamente no link. Como o comportamento seguro de anular window.opener agora é o padrão do navegador, rel='opener' é a forma de restaurar deliberadamente a referência ao opener, por exemplo quando um popup precisa enviar uma mensagem de volta para a página que o abriu. Isso reverte o comportamento implícito de noopener para aquele link específico, sem afetar os demais.