Voltar ao blog

Cabeçalhos de segurança: HSTS, CSP, X-Frame-Options e outros

· 7 min de leitura

O backend é uma fortaleza, mas metade da defesa está no navegador. HSTS, CSP e outros cabeçalhos bloqueiam XSS, clickjacking e MITM - e são grátis.

Cabeçalhos de segurança: HSTS, CSP, X-Frame-Options e outros

Porque importam

Uma aplicação pode ser perfeitamente segura no backend e ainda assim continuar vulnerável a ataques do lado do navegador: cross-site scripting (XSS), clickjacking, protocol downgrade, MIME confusion. Os cabeçalhos de segurança levam a defesa para o próprio navegador.

Strict-Transport-Security (HSTS)

Força HTTPS para todas as visitas futuras. Após a primeira visita por HTTPS, o navegador memoriza o domínio e reescreve por si mesmo qualquer link http:// para https://, mesmo que o utilizador clique num link errado.

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
  • max-age=63072000 = válido 2 anos
  • includeSubDomains = a regra aplica-se também a todos os subdomínios; força HTTPS em todo o lado, por isso um subdomínio a correr só por HTTP, p. ex. staging.example.com, fica inacessível no navegador
  • preload = permite a inclusão na lista HSTS preload integrada no Chrome / Firefox / Safari

Atenção: Remover um HSTS com preload da lista demora 6+ meses. Não adiciones preload antes de verificares que o HTTPS funciona de forma estável em todos os subdomínios.

Content-Security-Policy (CSP)

O cabeçalho mais poderoso, mas também o mais difícil de configurar. Faz whitelist de onde o navegador pode carregar scripts, estilos, imagens e iframes. Sem CSP, um atacante que consiga injetar uma tag <script> pode executar qualquer JS; com CSP, apenas código de fontes aprovadas.

Content-Security-Policy: default-src 'self'; script-src 'self' 'sha256-...'; img-src 'self' data: https://cdn.example.com; style-src 'self' 'unsafe-inline'; frame-ancestors 'none'

Diretivas comuns:

  • default-src 'self' = por defeito, permitir apenas recursos do meu próprio domínio
  • script-src = fontes JS (para scripts inline indica um hash ou nonce)
  • style-src = fontes CSS
  • img-src = imagens
  • connect-src = AJAX, WebSocket, EventSource
  • frame-ancestors 'none' = ninguém pode incorporar a página num iframe (melhor que X-Frame-Options)
  • report-uri /csp-report = o navegador envia um JSON em cada violação (apanha-la no backend e fazes log)
  • Nota: report-uri está hoje deprecated - os navegadores com suporte a report-to ignoram-no. A forma moderna é a diretiva report-to mais um cabeçalho Reporting-Endpoints separado; deixa report-uri apenas como fallback para o Firefox, que ainda não suporta report-to.

X-Frame-Options

Alternativa mais antiga ao frame-ancestors. Previne o clickjacking, em que o atacante incorpora a tua página como iframe e a cobre com botões invisíveis.

X-Frame-Options: DENY

Valores: DENY (ninguém), SAMEORIGIN (apenas o meu domínio), ALLOW-FROM uri (deprecated).

X-Content-Type-Options

X-Content-Type-Options: nosniff

Desliga o MIME sniffing, de modo que o navegador respeita o Content-Type que o servidor devolveu. Sem isso, um atacante pode fazer upload de um ficheiro com tipo errado (ex. uma imagem que é na realidade HTML com script) e o navegador pode executá-lo como página web.

Referrer-Policy

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

Controla quanta informação sobre a página anterior o navegador envia no cabeçalho Referer ao clicar. O valor por defeito nos navegadores modernos já é strict-origin-when-cross-origin, mas definir o cabeçalho de forma explícita garante um comportamento consistente.

Permissions-Policy

Desliga as APIs de que não precisas, como câmara, microfone, GPS e geolocalização. Um atacante que explore XSS não pode pedir estas APIs.

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

Configuração prática em nginx

server {
  listen 443 ssl http2;
  server_name example.com;

  add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
  # omitimos preload aqui de propósito - adiciona-o só quando tiveres 100% de certeza (ver a armadilha do preload acima)
  add_header X-Content-Type-Options "nosniff" always;
  add_header X-Frame-Options "DENY" always;
  add_header Referrer-Policy "strict-origin-when-cross-origin" always;
  add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

  # CSP é extensa - define-a conforme a tua aplicação
  add_header Content-Security-Policy "default-src 'self'; script-src 'self'; ..." always;
}

A chave é always - sem ele, o nginx omite os cabeçalhos nas respostas de erro (4xx, 5xx).

Auditoria do estado atual

O mais fácil é uma ferramenta online. O nosso header check mostra-te que cabeçalhos faltam e quais estão errados. Para uma auditoria aprofundada, o securityheaders.com dá ainda uma pontuação A-F.

Conclusão

Os cabeçalhos de segurança são um dos melhores investimentos em segurança na relação esforço-ganho: tipicamente meia hora de setup no reverse proxy contra uma categoria inteira de ataques do lado do navegador. Uma auditoria uma vez por semestre no âmbito da manutenção regular é um mínimo razoável.

Auditoria gratuita de security headers

Sem registo, resultado em três segundos.

Testar o site →

Partilhar: Link copiado

Experimente o ePulz.io grátis - 7 dias sem cartão de crédito.

Criar conta