Hospede com segurança dados do usuário em aplicativos da Web modernos

David Dworken
David Dworken

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-Type cabeç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: sandbox para 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-origin e Cross-Origin-Embedder-Policy: require-corp para ativar o isolamento de origem cruzada.

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 que foo.exampleusercontent.com e bar.exampleusercontent.com sejam entre sites e, portanto, totalmente isolados um do outro.
  • Os URLs que correspondem a *.exampleusercontent.com/shim sã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 eventos message e 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/shim e usa postMessage para 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.