HTTP Security Headers: Content-Security-Policy, HSTS, X-Frame-Options

1. Introdução aos HTTP Security Headers

Headers de segurança HTTP são a primeira linha de defesa contra ataques comuns em aplicações web modernas. Eles instruem o navegador a adotar comportamentos específicos que previnem explorações como Cross-Site Scripting (XSS), clickjacking e ataques man-in-the-middle (MITM). A ausência desses headers pode transformar uma aplicação segura em um alvo fácil.

Para inspecionar headers no navegador, utilize as DevTools (aba Network) ou ferramentas de linha de comando como cURL:

curl -I https://suaaplicacao.com

A resposta mostrará headers como content-security-policy, strict-transport-security e x-frame-options, que exploraremos em detalhes.

2. Content-Security-Policy (CSP): Blindando contra XSS

O header Content-Security-Policy define uma política de fontes confiáveis para scripts, estilos e outros recursos carregados pela página. Ele funciona como uma lista de permissões: qualquer recurso fora da lista é bloqueado pelo navegador.

Diretivas principais:

  • default-src: política padrão para todos os tipos de recurso
  • script-src: fontes permitidas para scripts JavaScript
  • style-src: fontes permitidas para folhas de estilo
  • img-src: fontes permitidas para imagens

Exemplo de CSP restritivo:

Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' https://cdn.exemplo.com

Essa política permite apenas recursos do próprio domínio ('self'), exceto imagens que podem vir de um CDN específico. Scripts e estilos inline são bloqueados, eliminando vetores de XSS.

Para testar sem bloquear, use Content-Security-Policy-Report-Only:

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

Isso registra violações sem aplicar bloqueios, permitindo ajustes seguros.

3. CSP Avançado: Nonces, Hashes e Relatório de Violações

Para scripts inline dinâmicos (como os gerados por frameworks), use nonces — valores aleatórios gerados por requisição:

Content-Security-Policy: script-src 'nonce-abc123def456'

No HTML, o script inline recebe o mesmo nonce:

<script nonce="abc123def456">alert('Seguro!');</script>

Para scripts estáticos, utilize hashes SHA:

Content-Security-Policy: script-src 'sha256-ABC123...'

Configure o monitoramento de violações com report-uri (legado) ou report-to (moderno):

Content-Security-Policy: default-src 'self'; report-uri https://meuservidor.com/report
Content-Security-Policy: default-src 'self'; report-to csp-endpoint

Headers Report-To adicionais definem o endpoint real. Essa abordagem permite detectar tentativas de ataque em produção.

4. HTTP Strict Transport Security (HSTS): Forçando HTTPS

O header Strict-Transport-Security instrui o navegador a sempre usar HTTPS para o domínio, prevenindo ataques de downgrade como SSL stripping.

Parâmetros cruciais:

  • max-age: tempo (em segundos) que o navegador deve lembrar da política
  • includeSubDomains: aplica a política a todos os subdomínios
  • preload: permite inclusão em listas de pré-carregamento de navegadores

Exemplo prático:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

Cuidados: Comece com max-age baixo (ex.: 300 segundos) para teste, depois aumente gradualmente. Um max-age muito alto em ambiente incorreto pode causar lockout — usuários não conseguirão acessar via HTTP mesmo em redes internas.

5. X-Frame-Options: Combatendo Clickjacking

O header X-Frame-Options controla se a página pode ser exibida em iframes. Diretivas:

  • DENY: bloqueia qualquer iframe
  • SAMEORIGIN: permite apenas do mesmo domínio
  • ALLOW-FROM (obsoleto): permitia domínio específico (não use)

Exemplo:

X-Frame-Options: SAMEORIGIN

Para controle mais granular, prefira CSP frame-ancestors:

Content-Security-Policy: frame-ancestors 'self' https://app.externo.com

frame-ancestors é mais flexível e moderno, permitindo múltiplos domínios e substituindo X-Frame-Options. Se ambos forem usados, o CSP tem precedência em navegadores modernos.

Teste vulnerabilidade de clickjacking criando um HTML com iframe:

<iframe src="https://suaaplicacao.com" width="500" height="500"></iframe>

Se a página carregar, está vulnerável. Ferramentas como SecurityHeaders.com detectam automaticamente.

6. Headers Complementares: X-Content-Type-Options e Referrer-Policy

X-Content-Type-Options: nosniff previne MIME sniffing, forçando o navegador a respeitar o Content-Type declarado:

X-Content-Type-Options: nosniff

Referrer-Policy controla informações de referência enviadas em requisições:

Referrer-Policy: strict-origin-when-cross-origin

Essa política envia a URL completa apenas para origens seguras, e apenas a origem para origens inseguras.

Permissions-Policy (antiga Feature-Policy) restringe APIs sensíveis:

Permissions-Policy: geolocation=(), camera=(), microphone=()

Isso bloqueia acesso a geolocalização, câmera e microfone por padrão.

7. Implementação Prática e Boas Práticas

Exemplo de configuração para Nginx:

add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-${request_id}'" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

Para Apache:

Header always set Content-Security-Policy "default-src 'self'; script-src 'self'"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Frame-Options "SAMEORIGIN"

Checklist de deploy:

  1. Teste em staging com Content-Security-Policy-Report-Only
  2. Use max-age progressivo para HSTS (300s → 86400s → 31536000s)
  3. Verifique com SecurityHeaders.com e Mozilla Observatory
  4. Monitore relatórios de violação CSP
  5. Tenha plano de rollback (remover headers ou reduzir max-age)

8. Erros Comuns e Mitigação

CSP muito permissivo: Evite 'unsafe-inline' e 'unsafe-eval'. Se necessário, use nonces ou hashes. Exemplo de CSP permissivo e perigoso:

Content-Security-Policy: default-src 'self' 'unsafe-inline' 'unsafe-eval' https://*

Isso anula a proteção contra XSS.

HSTS com max-age baixo: Valores como max-age=300 não protegem contra ataques persistentes. Aumente gradualmente até 31536000 (1 ano).

Conflito X-Frame-Options e frame-ancestors: Se ambos forem usados, frame-ancestors prevalece em navegadores modernos. Para consistência, use apenas CSP.

Sem monitoramento de violações: Configurar CSP sem report-uri ou report-to é como ter alarme sem sirene. Sempre colete relatórios para ajustar a política.

Referências