Como tornar seu site "isolado de origem cruzada" usando COOP e COEP

Use COOP e COEP para configurar um ambiente isolado de origem cruzada e ativar recursos avançados, como SharedArrayBuffer, performance.measureUserAgentSpecificMemory() e timer de alta resolução, com melhor precisão.

Atualizações

  • 21 de junho de 2022: os scripts de worker também precisam de cuidado quando o isolamento de origem cruzada está ativado. Adicionamos algumas explicações.
  • 5 de agosto de 2021: a API JS Self-Profiling foi mencionada como uma das APIs que exigem isolamento de origem cruzada, mas, refletindo uma mudança recente de direção, ela foi removida.
  • 6 de maio de 2021: com base no feedback e nos problemas informados, decidimos ajustar o cronograma para o uso do SharedArrayBuffer em nenhum site isolado de origem cruzada para que fique restrito no Chrome M92.
  • 16 de abril de 2021: adicionamos notas sobre um novo modo sem credenciais COEP e popups de mesma origem COOP para serem uma condição relaxada para isolamento de origem cruzada.
  • 5 de março de 2021: removemos limitações para SharedArrayBuffer, performance.measureUserAgentSpecificMemory() e funcionalidades de depuração, que agora estão totalmente ativadas no Chrome 89. Foram adicionados os próximos recursos, performance.now() e performance.timeOrigin, que terão maior precisão.
  • 19 de fevereiro de 2021: adicionamos uma observação sobre a política de recursos allow="cross-origin-isolated" e a funcionalidade de depuração no DevTools.
  • 15 de outubro de 2020: o self.crossOriginIsolated está disponível no Chrome 87. Refletindo que, document.domain é imutável quando self.crossOriginIsolated retorna true. O performance.measureUserAgentSpecificMemory() está encerrando o teste de origem e está ativado por padrão no Chrome 89. O Buffer de matriz compartilhado no Android Chrome estará disponível a partir do Chrome 88.

Algumas APIs da Web aumentam o risco de ataques de canal lateral, como o Spectre. Para reduzir esse risco, os navegadores oferecem um ambiente isolado com base na permissão chamado isolamento de origem cruzada. Com um estado isolado de origem cruzada, a página da Web poderá usar recursos privilegiados, incluindo:

API Descrição
SharedArrayBuffer Obrigatório para linhas de execução do WebAssembly. Disponível a partir do Android Chrome 88. No momento, a versão para computador é ativada por padrão com a ajuda do Isolamento de sites, mas exige o estado isolado de origem cruzada e será desativado por padrão no Chrome 92.
performance.measureUserAgentSpecificMemory() Disponível a partir do Chrome 89.
performance.now() e performance.timeOrigin Atualmente disponível em muitos navegadores com resolução limitada a 100 microssegundos ou mais. Com o isolamento de origem cruzada, a resolução pode ser de cinco microssegundos ou mais.
Recursos que estarão disponíveis no estado isolado de origem cruzada.

O estado isolado de origem cruzada também impede modificações de document.domain. A capacidade de alterar document.domain permite a comunicação entre documentos do mesmo site e foi considerada uma brecha na política de mesma origem.

Para ativar um estado isolado de origem cruzada, é preciso enviar os seguintes cabeçalhos HTTP no documento principal:

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

Esses cabeçalhos instruem o navegador a bloquear o carregamento de recursos ou iframes que não optaram por serem carregados por documentos de origem cruzada e impedem que janelas de origem cruzada interajam diretamente com o documento. Isso também significa que os recursos que estão sendo carregados em origens cruzadas exigem permissão.

Para determinar se uma página da Web está em um estado isolado de origem cruzada, examine self.crossOriginIsolated.

Este artigo mostra como usar esses novos cabeçalhos. Em um artigo de acompanhamento, vou fornecer mais informações e contexto.

Implante o COOP e o COEP para isolar as origens cruzadas do seu site

Integre COOP e COEP

1. Defina o cabeçalho Cross-Origin-Opener-Policy: same-origin no documento de nível superior

Ao ativar COOP: same-origin em um documento de nível superior, as janelas com a mesma origem e as abertas a partir do documento terão um grupo de contexto de navegação separado, a menos que estejam na mesma origem com a mesma configuração de COOP. Assim, o isolamento é aplicado para janelas abertas e a comunicação mútua entre as duas janelas é desativada.

Um grupo de contexto de navegação é um conjunto de janelas que podem referenciar umas às outras. Por exemplo, um documento de nível superior e os documentos filhos dele incorporados usando <iframe>. Se um site (https://a.example) abrir uma janela pop-up (https://b.example), a janela de abertura e a janela pop-up compartilharão o mesmo contexto de navegação. Portanto, elas terão acesso entre si usando APIs DOM, como window.opener.

Grupo de contexto de navegação

É possível verificar se o usuário que abre a janela está em grupos de contexto de navegação separados do DevTools (link em inglês).

2. Verifique se os recursos estão com o CORP ou o CORS ativado

Verifique se todos os recursos da página estão carregados com os cabeçalhos HTTP CORP ou CORS. Essa etapa é necessária para a etapa quatro, como ativar a COEP.

Veja o que você precisa fazer de acordo com a natureza do recurso:

  • Se quiser que o recurso seja carregado apenas da mesma origem, defina o cabeçalho Cross-Origin-Resource-Policy: same-origin.
  • Se o recurso for carregado somente do mesmo site, mas de origem cruzada, defina o cabeçalho Cross-Origin-Resource-Policy: same-site.
  • Se o recurso for carregado de origens cruzadas sob seu controle, defina o cabeçalho Cross-Origin-Resource-Policy: cross-origin, se possível.
  • Para recursos de origem cruzada que você não tem controle sobre:
    • Use o atributo crossorigin na tag HTML de carregamento se o recurso for veiculado com o CORS. Por exemplo, <img src="***" crossorigin>.
    • Peça ao proprietário do recurso para oferecer suporte ao CORS ou CORP.
  • Para iframes, siga os mesmos princípios acima e defina o Cross-Origin-Resource-Policy: cross-origin (ou same-site, same-origin, dependendo do contexto).
  • Os scripts carregados com um WebWorker precisam ser disponibilizados da mesma origem. Portanto, você não precisa de cabeçalhos CORP ou CORS.
  • Para um documento ou um worker disponibilizado com COEP: require-corp, os sub-recursos de origem cruzada carregados sem CORS precisam definir o cabeçalho Cross-Origin-Resource-Policy: cross-origin para aceitar a incorporação. Por exemplo, isso se aplica a <script>, importScripts, <link>, <video>, <iframe> etc.

3. Use o cabeçalho HTTP Apenas relatórios COEP para avaliar os recursos incorporados

Antes de ativar totalmente o COEP, faça uma simulação usando o cabeçalho Cross-Origin-Embedder-Policy-Report-Only para examinar se a política realmente funciona. Você receberá relatórios sem bloquear o conteúdo incorporado.

Aplique isso de forma recursiva a todos os documentos, incluindo o documento de nível superior, iframes e scripts de worker. Para mais informações sobre o cabeçalho HTTP somente relatório, consulte Observar problemas usando a API Reporting.

4. Ativar COEP

Depois de confirmar que tudo funciona e que todos os recursos podem ser carregados, mude o cabeçalho Cross-Origin-Embedder-Policy-Report-Only para Cross-Origin-Embedder-Policy com o mesmo valor para todos os documentos, incluindo aqueles incorporados por iframes e scripts de worker.

Determinar se o isolamento com self.crossOriginIsolated foi bem-sucedido

A propriedade self.crossOriginIsolated retorna true quando a página da Web está em um estado isolado de origem cruzada e todos os recursos e janelas são isolados no mesmo grupo de contexto de navegação. É possível usar essa API para determinar se você isolou o grupo de contexto de navegação e recebeu acesso a recursos avançados, como performance.measureUserAgentSpecificMemory().

Depurar problemas usando o Chrome DevTools

Para recursos renderizados na tela, como imagens, é fácil detectar problemas de COEP, porque a solicitação será bloqueada e a página vai indicar que falta uma imagem. No entanto, para recursos que não necessariamente têm um impacto visual, como scripts ou estilos, os problemas de COEP podem passar despercebidos. Para isso, use o painel Network do DevTools. Se houver um problema com o COEP, você verá (blocked:NotSameOriginAfterDefaultedToSameOriginByCoep) na coluna Status.

Problemas de COEP na coluna &quot;Status&quot; do painel &quot;Rede&quot;.

Em seguida, clique na entrada para ver mais detalhes.

Os detalhes do problema com a COEP serão mostrados na guia &quot;Cabeçalhos&quot; depois que você clicar em um recurso de rede no painel &quot;Rede&quot;.

Também é possível determinar o status de iframes e janelas pop-up usando o painel Application. Acesse a seção "Frames" no lado esquerdo e abra a "parte de cima" para conferir o detalhamento da estrutura de recursos.

É possível verificar o status do iframe, como a disponibilidade de SharedArrayBuffer etc.

Inspetor de iframe do Chrome DevTools

Também é possível conferir o status das janelas pop-up, por exemplo, se elas são isoladas de origem cruzada.

Inspetor de janelas pop-up do Chrome DevTools

Observar problemas usando a API Reporting

A API Reporting é outro mecanismo que permite detectar vários problemas. É possível configurar a API Reporting para instruir o navegador dos usuários a enviar um relatório sempre que o COEP bloquear o carregamento de um recurso ou o COOP isolar uma janela pop-up. O Chrome oferece suporte à API Reporting desde a versão 69 para diversos usos, incluindo COEP e COOP.

Para saber como configurar a API Reporting e um servidor para receber relatórios, consulte Como usar a API Reporting.

Exemplo de relatório COEP

Um exemplo de payload de relatório COEP quando o recurso de origem cruzada é bloqueado é semelhante ao seguinte:

[{
  "age": 25101,
  "body": {
    "blocked-url": "https://third-party-test.glitch.me/check.svg?",
    "blockedURL": "https://third-party-test.glitch.me/check.svg?",
    "destination": "image",
    "disposition": "enforce",
    "type": "corp"
  },
  "type": "coep",
  "url": "https://cross-origin-isolation.glitch.me/?coep=require-corp&coop=same-origin&",
  "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4249.0 Safari/537.36"
}]

Exemplo de relatório COOP

Um exemplo de payload do relatório COOP (em inglês) quando uma janela pop-up é aberta isolada tem a seguinte aparência:

[{
  "age": 7,
  "body": {
    "disposition": "enforce",
    "effectivePolicy": "same-origin",
    "nextResponseURL": "https://third-party-test.glitch.me/popup?report-only&coop=same-origin&",
    "type": "navigation-from-response"
  },
  "type": "coop",
  "url": "https://cross-origin-isolation.glitch.me/coop?coop=same-origin&",
  "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4246.0 Safari/537.36"
}]

Quando diferentes grupos de contexto de navegação tentam acessar uns aos outros (somente no modo "somente relatório"), o COOP também envia um relatório. Por exemplo, um relatório ao tentar usar postMessage() ficaria assim:

[{
  "age": 51785,
  "body": {
    "columnNumber": 18,
    "disposition": "reporting",
    "effectivePolicy": "same-origin",
    "lineNumber": 83,
    "property": "postMessage",
    "sourceFile": "https://cross-origin-isolation.glitch.me/popup.js",
    "type": "access-from-coop-page-to-openee"
  },
  "type": "coop",
  "url": "https://cross-origin-isolation.glitch.me/coop?report-only&coop=same-origin&",
  "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4246.0 Safari/537.36"
},
{
  "age": 51785,
  "body": {
    "disposition": "reporting",
    "effectivePolicy": "same-origin",
    "property": "postMessage",
    "type": "access-to-coop-page-from-openee"
  },
  "type": "coop",
  "url": "https://cross-origin-isolation.glitch.me/coop?report-only&coop=same-origin&",
  "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4246.0 Safari/537.36"
}]

Conclusão

Use uma combinação dos cabeçalhos HTTP COOP e COEP para ativar um estado isolado especial de origem cruzada em uma página da Web. Você pode analisar o self.crossOriginIsolated para determinar se uma página da Web está em estado isolado de origem cruzada.

Manteremos esta postagem atualizada à medida que novos recursos forem disponibilizados para esse estado isolado de origem cruzada, e outras melhorias forem feitas no DevTools em torno da COOP e da COEP.

Recursos