Um site criado por IA pode abrir login, checkout, documentação ou prévias em outra janela. Também pode ser aberto por um serviço externo que espera manter uma referência em window.opener. Esses fluxos parecem simples até uma política de isolamento separar as janelas em grupos diferentes e a integração perder o canal que usava.

Cross-Origin-Opener-Policy, ou COOP, permite que a resposta do documento defina como ele compartilha um grupo de contextos de navegação com páginas de outras origens. A política pode reduzir a superfície de ataques entre janelas e participa do isolamento necessário para APIs sensíveis, mas não deve ser adicionada sem inventariar pop-ups e retornos.

Este guia mostra como escolher uma COOP, testar login e pagamento, usar report-only e verificar a versão publicada.

Entenda a fronteira que COOP altera

Uma página aberta com window.open() pode receber uma referência para a janela que a abriu. A página original também recebe uma referência para a janela nova. A política de mesma origem já limita o que uma origem acessa da outra, mas algumas propriedades e relações entre os contextos continuam observáveis.

COOP atua no nível do grupo de contextos. Quando a navegação exige uma troca de grupo, referências entre janelas podem parecer fechadas ou deixar de oferecer a relação esperada.

Isso é diferente de:

  • rel="noopener", aplicado a um link ou abertura específica;
  • postMessage, que define um protocolo explícito entre janelas;
  • CSP frame-ancestors, que controla quem pode incorporar uma página;
  • iframe sandbox, que restringe capacidades do documento incorporado;
  • CORS, que controla a leitura de respostas pelo JavaScript.

O HTML Living Standard define os valores e as trocas de grupo de COOP. Use a especificação como fonte de comportamento; mensagens do console são apenas evidência de uma execução.

Inventarie quem abre e quem é aberto

Procure links, chamadas de JavaScript, SDKs e retornos de autenticação:

Terminal window
rg -n \
'window\.open|target=["'"']_blank|opener|postMessage|BroadcastChannel|oauth|checkout|popup' \
src public

Para cada fluxo, registre:

página que inicia a abertura:
origem da página inicial:
URL e redirects da janela aberta:
origem final:
quem precisa de window.opener:
mensagens enviadas e recebidas:
como o sucesso é confirmado no backend:
comportamento quando a janela fecha:
política COOP de cada resposta:
fallback sem referência entre janelas:

Inclua SDKs que criam pop-ups internamente. A ausência de window.open no código do projeto não prova que login, pagamento ou suporte não dependem de uma janela auxiliar.

Revise também janelas nomeadas. Um código pode reutilizar uma janela com window.open(url, "pagamento"), criando dependência entre navegações que não aparece em links com _blank.

Escolha o valor pelo fluxo necessário

As opções centrais são:

Valor Intenção prática
unsafe-none mantém o comportamento padrão, sem isolamento solicitado por COOP
same-origin-allow-popups isola navegações incompatíveis, preservando mais compatibilidade com certos pop-ups
same-origin separa documentos cross-origin em outro grupo e é a base para isolamento completo

Não escolha same-origin apenas porque parece mais forte. Se um login ou checkout cross-origin depende de window.opener, a mudança pode interromper o retorno mesmo que a interface do provedor continue abrindo.

same-origin-allow-popups existe para cenários em que a página precisa manter determinadas relações com pop-ups que não adotaram uma política equivalente. Trate-o como uma decisão de compatibilidade específica, não como substituto automático de same-origin.

O padrão sem header é unsafe-none. Isso não significa que a página está vulnerável por definição nem que COOP é necessária em toda landing page. A política deve responder a um modelo de ameaça, a relações entre janelas ou a uma necessidade real de isolamento cross-origin.

Comece com report-only quando houver pop-ups

COOP possui um header de observação:

Cross-Origin-Opener-Policy-Report-Only: same-origin; report-to="coop"
Reporting-Endpoints: coop="https://relatorios.exemplo/coop"

O modo report-only ajuda a descobrir acessos que seriam afetados sem aplicar a troca de grupo naquele momento. Use um endpoint controlado, retenção curta e filtros para não transformar relatórios em coleta indiscriminada.

A orientação de rollout do W3C WebAppSec descreve tipos de violação relacionados a opener e openee. Correlacione cada relatório com uma ação reproduzível; não afrouxe a política apenas porque houve volume.

Teste pelo menos:

  • abrir e concluir login;
  • cancelar login e fechar a janela;
  • iniciar e retornar de checkout;
  • abrir documentação ou suporte;
  • receber mensagens de sucesso e erro;
  • navegar por redirects intermediários;
  • repetir o fluxo com bloqueador de pop-ups;
  • executar o fallback sem window.opener.

Report-only não prova que o fluxo final está correto em todos os navegadores. Depois de corrigir dependências, aplique a política em um ambiente controlado e repita a matriz.

Não use window.opener como prova de autenticação

Uma janela pode informar que terminou o fluxo, mas o frontend não deve aceitar essa mensagem como prova final de login, pagamento ou autorização.

Se houver postMessage, valide:

window.addEventListener("message", (event) => {
if (event.origin !== "https://conta.exemplo") return;
if (event.source !== popup) return;
if (event.data?.type !== "login-complete") return;
void confirmarSessaoNoBackend();
});

Origem, janela e schema reduzem mensagens indevidas. A confirmação do estado crítico continua no servidor. O guia de uso seguro de postMessage detalha esse protocolo.

Para links comuns, mantenha a proteção local descrita no guia de reverse tabnabbing. COOP amplia a fronteira da resposta inteira, enquanto noopener expressa a intenção de uma abertura específica.

Combine com COEP somente quando houver motivo

Cross-Origin-Opener-Policy: same-origin participa do isolamento cross-origin, mas não o completa sozinho. Um documento também precisa de uma Cross-Origin-Embedder-Policy compatível e de um contexto seguro para que crossOriginIsolated possa se tornar verdadeiro.

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

Essa combinação pode ser necessária para recursos como SharedArrayBuffer e temporização de maior precisão. Ela também altera o carregamento de recursos e documentos externos. Não ative COEP para “completar” a configuração antes de inventariar imagens, fontes, scripts, workers, frames e APIs.

O guia de Cross-Origin-Embedder-Policy mostra essa segunda metade e os impactos de require-corp e credentialless.

Entregue o header na resposta real

COOP é um header de resposta HTTP:

Cross-Origin-Opener-Policy: same-origin

Uma meta tag não substitui esse header. Um arquivo com o nome _headers também não produz efeito por existir dentro do pacote.

O contrato atual de Publicação envia os arquivos preparados pelo projeto, mas não interpreta _headers como configuração da resposta. Se a aplicação precisa de COOP, confirme uma camada autorizada que entregue o header no HTML, como uma origem ou proxy administrado pela equipe ou suporte explícito da plataforma.

Registre a limitação como requisito de infraestrutura quando essa camada ainda não existe. Não marque a tarefa como concluída com base apenas no repositório.

Verifique a URL final e cada domínio

Depois do deploy, confira a resposta:

Terminal window
curl -sS -D - -o /dev/null https://exemplo.sitenoar.app \
| rg -i '^cross-origin-opener-policy:'

No navegador, repita os fluxos e registre:

console.table({
crossOriginIsolated,
hasOpener: window.opener !== null,
});

crossOriginIsolated: false não demonstra falha de COOP isoladamente; COEP, contexto seguro, Permissions Policy e recursos carregados também participam do resultado. Verifique headers e comportamento separadamente.

Repita na URL padrão e em cada domínio próprio ativo. A origem muda com esquema, host e porta, e um fluxo que funciona em preview pode usar uma allowlist ou redirect incompatível com o endereço final.

Quando ajustar headers ou integrações, gere uma nova versão e republique o mesmo Site para preservar o endereço já aprovado.

Prompt copiável para o agente

Revise e proponha uma Cross-Origin-Opener-Policy para este site.
Pasta publicável: [caminho]
URL de teste: [URL]
Domínios finais: [lista]
Login, checkout e pop-ups: [lista]
- Inventarie window.open, target=_blank, janelas nomeadas, SDKs e redirects.
- Registre quem depende de opener, openee, postMessage ou BroadcastChannel.
- Compare unsafe-none, same-origin-allow-popups e same-origin.
- Comece com report-only quando houver relações entre janelas.
- Teste sucesso, cancelamento, fechamento e fallback de cada pop-up.
- Não trate mensagens da janela como prova final de autenticação ou pagamento.
- Combine com COEP somente se houver requisito de isolamento cross-origin.
- Confirme que o header é entregue na resposta HTTP real.
- Verifique URL padrão, domínios próprios e todos os redirects.
- Entregue política escolhida, incompatibilidades e evidências.

Checklist final

  • links, pop-ups, SDKs e janelas nomeadas foram inventariados;
  • origens e redirects de cada fluxo estão documentados;
  • dependências de window.opener e postMessage são explícitas;
  • o valor de COOP atende ao fluxo e ao modelo de ameaça;
  • report-only foi analisado antes do enforcement quando necessário;
  • login, checkout, cancelamento e fallback foram testados;
  • estados críticos são confirmados no backend;
  • COEP não foi ativada sem inventário de recursos;
  • o header aparece na resposta HTTP final;
  • URL padrão e domínios próprios foram verificados;
  • a versão publicada corresponde à política aprovada.

COOP não é um selo genérico de segurança. É uma decisão sobre quais páginas podem permanecer no mesmo grupo de navegação e quais integrações precisam atravessar essa fronteira por um protocolo explícito e testado.