Muitos aplicativos da Web precisam mostrar conteúdo controlado pelo usuário. Isso pode ser tão simples quanto veicular imagens enviadas pelo usuário (por exemplo, fotos de perfil) ou tão complexo quanto renderizar HTML controlado pelo usuário (por exemplo, um tutorial de desenvolvimento da Web). Sempre foi difícil fazer isso com segurança. Por isso, trabalhamos para encontrar soluções fáceis, mas seguras, que podem ser aplicadas à maioria dos tipos de aplicativos da Web.
Soluções clássicas para isolar conteúdo não confiável
A solução clássica para veicular conteúdo controlado pelo usuário com segurança é usar o que é conhecido como domínios de sandbox. A ideia básica é que, se o domínio principal do aplicativo for example.com, você poderá veicular todo o conteúdo não confiável em exampleusercontent.com. Como esses dois domínios são entre sites, qualquer conteúdo malicioso em exampleusercontent.com não pode afetar example.com.
Essa abordagem pode ser usada para veicular com segurança todos os tipos de conteúdo não confiável, incluindo imagens, downloads e HTML. Embora possa não parecer necessário usar isso para imagens ou downloads, fazer isso ajuda a evitar riscos de detecção de conteúdo, especialmente em navegadores legados.
Os domínios de sandbox são amplamente usados no setor e funcionam bem há muito tempo. No entanto, eles têm duas desvantagens principais:
- Os aplicativos geralmente precisam restringir o acesso ao conteúdo a um único usuário, o que exige a implementação de autenticação e autorização. Como os domínios de sandbox não compartilham cookies com o domínio principal do aplicativo, isso é muito difícil de fazer com segurança. Para oferecer suporte à autenticação, os sites precisam usar URLs de capacidade ou definir cookies de autenticação separados para o domínio de sandbox. Esse segundo método é especialmente problemático na Web moderna, em que muitos navegadores restringem cookies entre sites por padrão.
- Embora o conteúdo do usuário esteja isolado do site principal, ele não está isolado de outros conteúdos do usuário. Isso cria o risco de conteúdo do usuário mal-intencionado atacar outros dados no domínio de sandbox (por exemplo, lendo dados da mesma origem).
Também vale a pena observar que os domínios de sandbox ajudam a mitigar os riscos de phishing, já que os recursos são claramente segmentados em um domínio isolado.
Soluções modernas para veicular conteúdo do usuário
Com o tempo, a Web evoluiu, e agora há maneiras mais fáceis e seguras de veicular conteúdo não confiável. Há muitas abordagens diferentes. Por isso, vamos descrever duas soluções que usamos no Google.
Abordagem 1: veicular conteúdo do usuário inativo
Se um site só precisar veicular conteúdo do usuário inativo (ou seja, conteúdo que não seja HTML ou JavaScript, por exemplo, imagens e downloads), isso poderá ser feito com segurança sem um domínio de sandbox isolado. Há duas etapas principais:
- Sempre defina o
Content-Typecabeçalho como um tipo MIME conhecido que seja compatível com todos os navegadores e não contenha conteúdo ativo. Em caso de dúvida,application/octet-streamé uma opção segura. - Além disso, sempre defina os cabeçalhos de resposta para garantir que o navegador isole totalmente a resposta.
| Cabeçalho de resposta | Purpose |
|---|---|
X-Content-Type-Options: nosniff |
Impede a detecção de conteúdo |
Content-Disposition: attachment; filename="download" |
Aciona um download em vez da renderização |
Content-Security-Policy: sandbox |
Coloca o conteúdo em sandbox como se ele fosse veiculado em um domínio separado |
Content-Security-Policy: default-src ‘none' |
Desativa a execução de JavaScript (e a inclusão de sub-recursos) |
Cross-Origin-Resource-Policy: same-site |
Impede que a página seja incluída entre sites |
Essa combinação de cabeçalhos garante que a resposta só possa ser carregada como um sub-recurso pelo aplicativo ou baixada como um arquivo pelo usuário. Além disso, os cabeçalhos oferecem várias camadas de proteção contra bugs do navegador pelo cabeçalho de sandbox CSP e pela restrição default-src. Em geral, a configuração descrita oferece um alto grau de confiança de que as respostas veiculadas dessa forma não podem levar a vulnerabilidades de injeção ou isolamento.
Defesa em profundidade
Embora a solução proposta represente uma defesa geralmente suficiente contra XSS, há várias outras medidas de reforço da proteção que podem ser aplicadas para fornecer camadas adicionais de segurança:
- Defina um cabeçalho
X-Content-Security-Policy: sandboxpara compatibilidade com o IE11. - Defina um cabeçalho
Content-Security-Policy: frame-ancestors 'none'para impedir que o endpoint seja incorporado. - Coloque o conteúdo do usuário em sandbox em um subdomínio isolado:
- Veicule o conteúdo do usuário em um subdomínio isolado (por exemplo, o Google usa domínios como
product.usercontent.google.com). - Defina
Cross-Origin-Opener-Policy: same-origineCross-Origin-Embedder-Policy: require-corppara ativar o isolamento de origem cruzada.
- Veicule o conteúdo do usuário em um subdomínio isolado (por exemplo, o Google usa domínios como
Abordagem 2: disponibilizar conteúdo do usuário ativo
A veiculação segura de conteúdo ativo (por exemplo, imagens HTML ou SVG) também pode ser feita sem as fraquezas da abordagem clássica de domínio de sandbox.
A opção mais simples é aproveitar o cabeçalho Content-Security-Policy: sandbox para informar ao navegador que ele isole a resposta. Embora nem todos os navegadores da Web implementem o isolamento de processos para documentos de sandbox, os refinamentos contínuos nos modelos de processo do navegador provavelmente vão melhorar a separação do conteúdo em sandbox dos aplicativos de incorporação. Se os ataques de comprometimento do SpectreJS e do renderizador estiverem fora do seu modelo de ameaça, o uso do sandbox CSP provavelmente será uma solução suficiente.
No Google, desenvolvemos uma solução que pode isolar totalmente o conteúdo ativo não confiável modernizando o conceito de domínios de sandbox. A ideia principal é:
- Criar um novo domínio de sandbox que seja adicionado à lista de sufixos públicos. Por exemplo, ao adicionar
exampleusercontent.comà PSL, você pode garantir quefoo.exampleusercontent.comebar.exampleusercontent.comsejam entre sites e, portanto, totalmente isolados um do outro. - Os URLs que correspondem a
*.exampleusercontent.com/shimsão todos roteados para um arquivo de shim estático. Esse arquivo de shim contém um pequeno snippet de HTML e JavaScript que detecta o manipulador de eventosmessagee renderiza qualquer conteúdo que ele receba. - Para usar isso, o produto cria um iframe ou uma caixa de diálogo para
$RANDOM_VALUE.exampleusercontent.com/shime usapostMessagepara enviar o conteúdo não confiável ao shim para renderização. - O conteúdo renderizado é transformado em um blob e renderizado dentro de um iframe em sandbox.
Em comparação com a abordagem clássica de domínio de sandbox, isso garante que todo o conteúdo seja totalmente isolado em um site exclusivo. Além disso, como o aplicativo principal lida com a recuperação dos dados a serem renderizados, não é mais necessário usar URLs de capacidade.
Conclusão
Juntas, essas duas soluções possibilitam a migração de domínios de sandbox clássicos, como googleusercontent.com, para soluções mais seguras que sejam compatíveis com o bloqueio de cookies de terceiros. No Google, já migramos muitos produtos para usar essas soluções e temos mais migrações planejadas para o próximo ano.