Content Security Policy (CSP): configurando proteção real contra XSS

1. Fundamentos da Content Security Policy

A Content Security Policy (CSP) é uma camada de segurança que permite aos desenvolvedores web controlar quais recursos podem ser carregados e executados em suas páginas. Diferente de abordagens tradicionais baseadas em blocklist (que tentam bloquear padrões conhecidos de ataque), a CSP opera com whitelist: você define explicitamente o que é permitido, e tudo o mais é automaticamente bloqueado pelo navegador.

Quando um navegador recebe o cabeçalho Content-Security-Policy, ele cria um ambiente restrito onde scripts inline, eval(), e requisições para origens não autorizadas são imediatamente rejeitados. Isso mitiga diretamente ataques XSS, injeção de script e data exfiltration, pois mesmo que um atacante consiga injetar código malicioso, o navegador se recusará a executá-lo.

A política pode ser definida via cabeçalho HTTP ou meta tag equivalente:

Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self'">

2. Diretivas Essenciais e Seus Efeitos Práticos

Cada diretiva CSP controla uma categoria específica de recursos:

  • default-src: atua como fallback para todas as diretivas não especificadas
  • script-src: controla fontes de scripts JavaScript
  • style-src: controla fontes de folhas de estilo CSS
  • img-src: restringe origens de imagens
  • font-src: limita fontes customizadas
  • connect-src: controla requisições AJAX, WebSocket e EventSource
  • object-src: bloqueia plugins como Flash e Java (recomendado: 'none')
  • frame-src: restringe iframes e incorporações
  • base-uri: previne manipulação de base URL para redirecionamento malicioso

Exemplo prático de configuração restritiva:

default-src 'self';
script-src 'self';
style-src 'self';
img-src 'self' https://images.unsplash.com;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.minhaapp.com;
object-src 'none';
frame-src 'none';
base-uri 'self'

3. Configuração Passo a Passo para Aplicações Web

O ponto de partida ideal é uma política mínima e segura:

default-src 'self'

Esta política permite apenas recursos do próprio domínio. Para aplicações modernas, precisamos expandir gradualmente. Considere uma aplicação React que usa Bootstrap via CDN e faz chamadas a uma API externa:

default-src 'self';
script-src 'self' https://cdn.jsdelivr.net;
style-src 'self' https://cdn.jsdelivr.net;
img-src 'self' data:;
connect-src 'self' https://api.minhaapp.com;
font-src 'self' https://cdn.jsdelivr.net;
object-src 'none';
frame-ancestors 'none';
base-uri 'self';
form-action 'self'

Para aplicações Vue ou Angular, adicione nonces para scripts inline:

script-src 'self' 'nonce-abc123' https://cdn.jsdelivr.net

4. Nonces e Hashes: Estratégias Avançadas de Inline Scripts

Nonces são valores únicos gerados por requisição que permitem a execução de scripts inline específicos. No servidor:

// Geração de nonce (exemplo em Node.js)
const crypto = require('crypto');
const nonce = crypto.randomBytes(16).toString('base64');
res.setHeader('Content-Security-Policy', `script-src 'nonce-${nonce}'`);

No HTML:

<script nonce="abc123">
  console.log('Script inline legítimo');
</script>

Para scripts inline estáticos, hashes SHA são mais adequados:

script-src 'sha256-ABC123DEF456...'

A diferença entre 'strict-dynamic' e whitelist tradicional é crucial: strict-dynamic permite que scripts carregados com nonce ou hash carreguem outros scripts dinamicamente, sem precisar listar cada origem. Isso é ideal para SPAs modernas:

script-src 'strict-dynamic' 'nonce-abc123' 'unsafe-inline' https:

5. Testando e Depurando Políticas CSP

O modo Content-Security-Policy-Report-Only permite testar políticas sem bloqueá-las:

Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report

Violações são enviadas como relatórios JSON para o endpoint especificado. Ferramentas essenciais:

  • Console do navegador: exibe violações CSP em tempo real
  • CSP Evaluator (csp-evaluator.withgoogle.com): analisa políticas e sugere melhorias
  • Relatórios de violação: colete e analise em produção com serviços como report-uri.io

Exemplo de relatório de violação:

{
  "csp-report": {
    "document-uri": "https://minhaapp.com/pagina",
    "blocked-uri": "https://evil.com/script.js",
    "violated-directive": "script-src 'self'",
    "effective-directive": "script-src"
  }
}

6. Armadilhas Comuns e Mitigação de Falsos Positivos

Problemas frequentes e soluções:

  1. eval() e setTimeout(string): bibliotecas como jQuery e Angular usam eval internamente. Solução: use 'unsafe-eval' temporariamente ou migre para versões compatíveis com CSP

  2. Extensões de navegador: extensões injetam scripts que violam a política. Use 'unsafe-inline' apenas como último recurso

  3. Bibliotecas com injeção dinâmica: se uma biblioteca cria elementos script dinamicamente, use 'strict-dynamic'

Estratégia de migração gradual:

// Fase 1: Report-Only
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report

// Fase 2: Política permissiva com relatório
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; report-uri /csp-report

// Fase 3: Política restritiva com nonces
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-abc123'; report-uri /csp-report

7. Integração com Pipeline de CI e Monitoramento Contínuo

Automatize a validação de CSP com ferramentas como csp-validator:

# Exemplo de comando no CI
npx csp-validator --policy "default-src 'self'" --url https://minhaapp.com

Para análise estática, use semgrep:

# Regra semgrep para detectar CSP ausente
rules:
  - id: missing-csp-header
    patterns:
      - pattern: |
          app.use(helmet())
      - pattern-not: |
          app.use(helmet.contentSecurityPolicy(...))

Em produção, configure coleta de relatórios:

Content-Security-Policy: default-src 'self'; report-uri https://meureport.io/csp

Pipeline completo:

  1. Build: gere nonces dinâmicos para cada build
  2. CI: valide política com csp-validator
  3. Deploy: aplique política com report-uri configurado
  4. Runtime: monitore relatórios de violação e ajuste gradualmente

Referências