Rudra Analyzer

Segurança

Content-Security-Policy explicada: diretivas, unsafe-inline, nonces e uma implantação segura

A CSP é o cabeçalho de segurança mais poderoso e o mais fácil de errar. As diretivas que importam, como nonces e hashes substituem o 'unsafe-inline' e um plano de implantação que não quebra o seu site.

Por Rudra Techno Team 8 min de leitura
Nesta página

A Content-Security-Policy (CSP) é um cabeçalho de resposta que diz ao navegador de onde uma página pode carregar scripts, estilos, imagens, frames e outros recursos. O papel principal dela é conter danos: se um invasor conseguir injetar um <script> na sua página por meio de uma falha de cross-site scripting (XSS), uma boa política impede o navegador de executá-lo.

O porém é que "uma CSP" e "uma boa CSP" são coisas bem diferentes. Um cabeçalho cheio de curingas passa em um teste de presença e não protege quase nada. Este guia explica como distinguir uma da outra.

Como uma política é montada

Uma política é uma lista de diretivas separadas por ponto e vírgula. Cada diretiva indica um tipo de recurso e as fontes permitidas para ele: Content-Security-Policy: default-src 'self'; img-src 'self' https://images.example-cdn.com; object-src 'none'.

As fontes podem ser 'self' (a sua própria origem), origens específicas como https://js.stripe.com, esquemas como https: ou data:, palavras-chave como 'none', ou nonces e hashes, explicados mais abaixo. As palavras-chave vão entre aspas simples; as origens, não.

As diretivas mais importantes

  • default-src: o valor de reserva para a maioria dos tipos de recurso que você não lista separadamente.
  • script-src: de onde os scripts podem vir. É a diretiva que de fato defende contra XSS, por isso merece o maior cuidado.
  • style-src, img-src, font-src, connect-src (fetch, XHR, WebSockets), frame-src e media-src: os demais tipos de recurso.
  • object-src 'none': bloqueia plugins como <object> e <embed>, um caminho antigo, mas ainda citado, para a execução de scripts.
  • base-uri 'self' ou 'none': impede que uma tag <base> injetada mude o destino das URLs relativas de scripts.
  • frame-ancestors: quais sites podem incorporar a sua página em um frame — o substituto moderno do X-Frame-Options.
  • form-action: para onde os formulários podem ser enviados.
  • upgrade-insecure-requests: pede ao navegador que carregue por HTTPS os sub-recursos em http://.
  • report-to / report-uri: para onde o navegador envia os relatórios de violação.

O que enfraquece uma política

'unsafe-inline'

Em script-src, 'unsafe-inline' libera todo bloco <script> inline e todo manipulador de evento inline, como onclick. É exatamente isso que um ataque de XSS injeta, de modo que uma política com 'unsafe-inline' para scripts mal chega a atrasá-lo. Os navegadores com suporte a nonces ou hashes ignoram 'unsafe-inline' quando há um deles presente, e é por isso que às vezes ele é mantido ao lado de um nonce, como reserva para navegadores muito antigos.

'unsafe-eval'

'unsafe-eval' libera eval(), new Function() e argumentos em formato de string para setTimeout. Ele transforma dados em código, o que é arriscado. Algumas bibliotecas e motores de template mais antigos precisam dele; os builds modernos, em geral, não.

Fontes amplas demais

*, https:, http: ou data: em script-src liberam scripts de praticamente qualquer lugar, de modo que um invasor pode hospedar o script dele em qualquer servidor HTTPS. As CDNs populares são um problema mais sutil: liberar o host inteiro de uma CDN pública permite a um invasor carregar qualquer biblioteca hospedada ali, inclusive versões antigas com formas conhecidas de burlar a política.

Report-Only sozinho

Content-Security-Policy-Report-Only reporta as violações, mas não bloqueia nada. É o jeito certo de começar e o lugar errado para parar.

Nonces e hashes: a saída para o 'unsafe-inline'

Um nonce é um valor aleatório que o seu servidor gera a cada resposta. Você o coloca no cabeçalho — script-src 'nonce-R4nd0mV4lue' — e em cada tag de script em que confia: <script nonce="R4nd0mV4lue">. O navegador executa apenas os scripts que trazem o nonce correspondente. Um script injetado não conhece o valor, por isso é bloqueado. O nonce precisa ser imprevisível e diferente em cada resposta; um nonce fixo não é melhor do que 'unsafe-inline'.

Um hash libera um script inline específico pelo hash SHA-256, SHA-384 ou SHA-512 do conteúdo dele: script-src 'sha256-…'. Os hashes servem bem a páginas estáticas, em que um nonce por resposta não é viável; qualquer alteração no script muda o hash.

Acrescentar 'strict-dynamic' permite que os scripts em que você confiou por nonce ou hash carreguem outros scripts e manda os navegadores compatíveis ignorarem as listas de hosts permitidos. Isso torna a chamada CSP estrita viável até em sites com gerenciadores de tags e widgets: script-src 'nonce-{random}' 'strict-dynamic'; object-src 'none'; base-uri 'none'.

Veja como a sua CSP é interpretada

O verificador de segurança gratuito do Rudra analisa a sua Content-Security-Policy diretiva por diretiva e sinaliza 'unsafe-inline', 'unsafe-eval', fontes de script amplas demais e a ausência de object-src ou base-uri.

Verifica sua página inicial · Grátis · Sem cadastro

Um plano de implantação que não quebra o seu site

  1. Faça o inventário do que a página carrega. Abra as ferramentas do desenvolvedor nas suas páginas principais — página inicial, login, checkout, páginas com conteúdo incorporado — e anote cada origem de script, estilo, fonte, frame e API.
  2. Envie uma política em Report-Only. Comece com algo como default-src 'self'; script-src 'self' 'nonce-{random}'; object-src 'none'; base-uri 'self' em Content-Security-Policy-Report-Only. As violações aparecem no console do navegador e no seu endpoint de relatórios, se você configurar um.
  3. Corrija ou libere cada violação. Mova os scripts inline para arquivos ou dê um nonce a eles, troque os manipuladores onclick inline por addEventListener e adicione as origens de terceiros específicas que você realmente usa.
  4. Aplique a política. Quando os relatórios ficarem silenciosos nas suas principais jornadas, troque o nome do cabeçalho para Content-Security-Policy. Você pode continuar enviando em paralelo uma política Report-Only mais rígida para testar o próximo passo.
  5. Mantenha a política em dia. Todo novo widget, ferramenta de analytics ou provedor de pagamento exige uma mudança na política. Verifique de novo depois de adicionar um.

Defina o cabeçalho no servidor, na CDN ou no framework, e não em uma tag <meta>, se puder evitar: uma política em meta tag não pode usar frame-ancestors, relatórios nem o modo Report-Only.

O que o Rudra verifica na sua política

O verificador de segurança de site gratuito lê a CSP que a sua página realmente envia e mostra as diretivas interpretadas como evidência. Ele sinaliza a ausência de política, uma política enviada apenas como Report-Only, uma política que não restringe scripts de forma alguma (sem script-src nem default-src), 'unsafe-inline' na política de scripts (não sinalizado quando há um nonce ou um hash), 'unsafe-eval', fontes de script amplas demais, como * ou https: (a menos que você use 'strict-dynamic' com um nonce ou um hash), e — como notas informativas — a falta de object-src 'none', a falta de base-uri e os estilos inline. Ele reconhece frame-ancestors como proteção contra clickjacking quando o valor não é * nem um esquema solto.

Um verificador consegue dizer o que a sua política permite. Não consegue dizer se as suas páginas continuam funcionando com ela — só testar as suas jornadas reais em modo report-only responde a isso.

Perguntas frequentes

Uma Content-Security-Policy impede XSS?

Ela não corrige a falha de origem, mas uma política estrita impede a execução da maioria dos scripts injetados, o que limita o estrago. Você continua precisando escapar a saída e validar a entrada.

'unsafe-inline' em style-src é um problema?

É bem menos grave do que em script-src. Estilos injetados ainda podem ser explorados em alguns ataques, então removê-lo é um bom reforço de segurança, mas priorize primeiro a política de scripts.

Posso usar o mesmo nonce em todas as páginas?

Não. Um nonce precisa ser aleatório e único em cada resposta. Um nonce fixo ou reutilizado pode ser copiado por um invasor e não oferece proteção nenhuma.

Por quanto tempo devo usar o Report-Only antes de aplicar a política?

Tempo suficiente para cobrir os seus padrões reais de tráfego — muitas vezes de uma a duas semanas —, incluindo login, checkout e todas as páginas com conteúdo incorporado de terceiros. Aplique a política quando os relatórios só mostrarem ruído, como extensões de navegador.

Precisa de uma análise mais profunda do seu site?

Veja todos os problemas do seu site, na ordem em que vale a pena corrigir

Verifique qualquer página gratuitamente, sem conta, ou cadastre-se para rastrear o site inteiro. Cada relatório cobre SEO, problemas comuns de desempenho, acessibilidade e segurança, com uma correção sugerida para cada problema.