Garantir que a CSP seja eficaz contra ataques XSS

Uma política de segurança de conteúdo (CSP) ajuda a garantir que qualquer conteúdo carregado na página seja confiável para o proprietário do site. As CSPs mitigam ataques de scripting em vários locais (XSS) porque podem bloquear scripts inseguros injetados por invasores. No entanto, o CSP pode ser facilmente ignorado se não for rigoroso o suficiente. Para mais informações, consulte Mitigar o scripting em vários locais (XSS) com uma Política de Segurança de Conteúdo (CSP) rígida. O Lighthouse coleta CSPs aplicadas no documento principal e informa problemas do CSP Evaluator se eles puderem ser ignorados.

Relatório do Lighthouse alertando que nenhuma CSP foi encontrada no modo restrito.
Aviso do relatório do Lighthouse de que nenhuma CSP foi encontrada no modo restrito.

Práticas obrigatórias para um CSP não bypassável

Implemente as práticas a seguir para garantir que o CSP não possa ser ignorado. Se o CSP puder ser ignorado, o Lighthouse vai emitir um aviso de alta gravidade.

CSPs segmentam XSS

Para segmentar XSS, a CSP precisa incluir as diretivas script-src, object-src e base-uri. O CSP também não pode ter erros de sintaxe.

script-src e object-src protegem uma página contra scripts e plug-ins não seguros, respectivamente. Como alternativa, o default-src pode ser usado para configurar uma política ampla em vez de muitas diretivas, incluindo script-src e object-src.

base-uri impede a injeção de tags <base> não autorizadas, que podem ser usadas para redirecionar todos os URLs relativos (como scripts) para um domínio controlado por invasores.

O CSP usa valores de uso único ou hashes para evitar desvios de listas de permissões

Um CSP que configura uma lista de permissões para script-src depende da suposição de que todas as respostas provenientes de um domínio confiável são seguras e podem ser executadas como scripts. No entanto, essa suposição não se aplica a aplicativos modernos. Alguns padrões comuns e benignos, como a exposição de interfaces JSONP e cópias de hospedagem da biblioteca AngularJS, permitem que os invasores escapem dos limites do CSP.

Na prática, embora possa não ser óbvio para os autores do aplicativo, a maioria das listas de permissões script-src pode ser contornada por um invasor com um bug XSS e oferece pouca proteção contra a injeção de scripts. Por outro lado, as abordagens baseadas em valor de uso único e em hash não têm esses problemas e facilitam a adoção e a manutenção de uma política mais segura.

Por exemplo, este código usa um endpoint JSONP hospedado em um domínio confiável para injetar um script controlado pelo invasor:

CSP:

script-src https://trusted.example.com

HTML:

<script src="https://trusted.example.com/path/jsonp?callback=alert(document.domain)//"></script>

Para evitar que isso aconteça, uma CSP precisa permitir scripts individualmente usando valores de uso único ou hashes e usar "strict-dynamic" em vez de uma lista de permissões.

Outras recomendações para um CSP seguro

Implemente as práticas a seguir para aumentar a segurança e a compatibilidade. Se o CSP não seguir uma das recomendações, o Lighthouse vai emitir um aviso de gravidade média.

Configurar os relatórios do CSP

Configurar um destino de relatório ajuda a monitorar falhas. É possível definir o destino dos relatórios usando as diretivas report-uri ou report-to. No momento, report-to não é compatível com todos os navegadores modernos. Por isso, recomendamos usar os dois ou apenas report-uri.

Se algum conteúdo violar o CSP, o navegador vai enviar um relatório para o destino configurado. Verifique se você tem um aplicativo configurado nesse destino para processar esses relatórios.

Definir a CSP em um cabeçalho HTTP

Uma CSP pode ser definida em uma metatag assim:

<meta http-equiv="Content-Security-Policy" content="script-src 'none'">

No entanto, se possível, defina uma CSP em um cabeçalho de resposta HTTP. Uma injeção antes da meta tag vai contornar o CSP. Além disso, frame-ancestors, sandbox e relatórios não são compatíveis com CSPs de metatag.

Conferir se a CSP é compatível com versões anteriores

Nem todos os navegadores oferecem suporte a valores de uso único/hashes de CSP. Portanto, é recomendável adicionar unsafe-inline como uma alternativa para navegadores não compatíveis. Se o navegador oferecer suporte a valores de uso único/hashes, unsafe-inline será ignorado.

Da mesma forma, strict-dynamic não é compatível com todos os navegadores. É recomendável definir uma lista de permissões como substituto para todos os navegadores não compatíveis. A lista de permissões será ignorada em navegadores compatíveis com strict-dynamic.

Como desenvolver um CSP estrito

Confira abaixo um exemplo de uso de um CSP rígido com uma política baseada em valor de uso único.

CSP:

script-src 'nonce-random123' 'strict-dynamic' 'unsafe-inline' https:;
object-src 'none';
base-uri 'none';
report-uri https://reporting.example.com;

HTML:

<script nonce="random123" src="https://trusted.example.com/trusted_script.js"></script>

random123 seria qualquer string base64 gerada do lado do servidor sempre que a página é carregada. unsafe-inline e https: são ignorados em navegadores modernos devido ao valor de uso único e ao strict-dynamic. Para mais informações sobre a adoção de um CSP rígido, consulte o guia de CSP rígido.

É possível verificar um CSP em busca de possíveis desvios usando o Lighthouse e o CSP Evaluator. Se você quiser testar um novo CSP sem o risco de quebrar as páginas atuais, defina o CSP no modo somente relatório usando Content-Security-Policy-Report-Only como o nome do cabeçalho. Isso vai enviar violações do CSP para todos os destinos de relatório que você configurou com report-to e report-uri, mas não vai aplicar o CSP.