Headers de segurança HTTP com Nginx
Headers HTTP de segurança instruem o browser a se proteger contra XSS, clickjacking, sniffing de MIME e outras vulnerabilidades — sem alterar uma linha do código da aplicação. Configurar esses headers no Nginx significa que todos os serviços por trás do proxy se beneficiam automaticamente.
Headers de segurança essenciais
Conjunto básico de headers que toda aplicação deveria ter:
# /etc/nginx/conf.d/security-headers.conf
# Incluir em todos os server blocks: include /etc/nginx/conf.d/security-headers.conf;
# Forçar HTTPS por 1 ano (HSTS)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# Prevenir clickjacking: não permitir incorporação em iframe
add_header X-Frame-Options "SAMEORIGIN" always;
# Prevenir MIME sniffing
add_header X-Content-Type-Options "nosniff" always;
# Controlar informações no Referer header
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Desabilitar FLoC/Topics API e outras features sensíveis
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), interest-cohort=()" always;
# Remover header Server (não revelar versão do Nginx)
server_tokens off;
# X-XSS-Protection (legacy — navegadores modernos ignoram)
add_header X-XSS-Protection "1; mode=block" always;Content Security Policy (CSP)
CSP é o header mais poderoso — define de onde cada tipo de recurso pode ser carregado:
# CSP básica para API (sem frontend):
add_header Content-Security-Policy "default-src 'none'; frame-ancestors 'none';" always;
# CSP para aplicação web completa:
add_header Content-Security-Policy "
default-src 'self';
script-src 'self' 'nonce-NONCE_AQUI' https://cdn.jsdelivr.net;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
img-src 'self' data: https://images.exemplo.com;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.seudominio.com.br wss://api.seudominio.com.br;
frame-ancestors 'none';
form-action 'self';
upgrade-insecure-requests;
" always;
# CSP Report-Only (testar sem bloquear — reportar violações):
add_header Content-Security-Policy-Report-Only "
default-src 'self';
report-uri https://api.seudominio.com.br/csp-report;
" always;
# Diretivas importantes:
# default-src 'self': apenas recursos do próprio domínio por padrão
# script-src 'nonce-XYZ': permitir apenas scripts com o nonce correto
# frame-ancestors 'none': substituiu X-Frame-Options (mais moderno)
# upgrade-insecure-requests: converter http:// para https:// automaticamenteConfigurar CORS com segurança
CORS (Cross-Origin Resource Sharing) para APIs acessadas por domínios diferentes:
# /etc/nginx/conf.d/cors.conf — CORS para API
# ATENÇÃO: nunca use Access-Control-Allow-Origin: * para APIs autenticadas
# Map para validar origins permitidas
map $http_origin $allowed_origin {
default "";
"https://app.seudominio.com.br" "https://app.seudominio.com.br";
"https://admin.seudominio.com.br" "https://admin.seudominio.com.br";
# Desenvolvimento:
"http://localhost:3000" "http://localhost:3000";
}
server {
location /api/ {
# Responder preflight OPTIONS
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin $allowed_origin;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With";
add_header Access-Control-Allow-Credentials "true";
add_header Access-Control-Max-Age 86400;
add_header Content-Length 0;
return 204;
}
# Headers CORS para requisições normais
add_header Access-Control-Allow-Origin $allowed_origin always;
add_header Access-Control-Allow-Credentials "true" always;
proxy_pass http://127.0.0.1:3000;
}
}Ocultar informações do servidor
Reduza a superfície de ataque ocultando versões de software:
# nginx.conf — bloco http {}
# Remover versão do Nginx dos headers e páginas de erro
server_tokens off;
# Remover header X-Powered-By do backend (Node.js)
# (o Nginx não pode remover headers do backend diretamente, mas pode sobrescrever)
proxy_hide_header X-Powered-By;
proxy_hide_header Server;
# Adicionar um Server header neutro:
add_header Server "VPS" always;
# Remover header X-AspNet-Version (se usar .NET):
proxy_hide_header X-AspNet-Version;
proxy_hide_header X-AspNetMvc-Version;
# No backend Node.js/Express — remover X-Powered-By:
# app.disable('x-powered-by')
# Ou usar helmet: app.use(helmet())
# Verificar headers retornados:
curl -I https://api.seudominio.com.br/
# Deve mostrar Server: VPS (não "nginx/1.25.3")Testar e verificar os headers
Ferramentas para validar que os headers estão configurados corretamente:
# Verificar headers com curl:
curl -s -I https://seudominio.com.br | grep -i "strict-transport\|x-frame\|content-security\|x-content"
# Teste online:
# https://securityheaders.com — análise completa com nota A-F
# https://observatory.mozilla.org — análise da Mozilla
# Verificar CSP com navegador (DevTools):
# F12 → Console → ver erros "Refused to load..." de violações CSP
# Script para verificar múltiplos headers de uma vez:
for HEADER in "Strict-Transport-Security" "X-Frame-Options" "X-Content-Type-Options" \
"Content-Security-Policy" "Referrer-Policy" "Permissions-Policy"; do
VALUE=$(curl -s -I https://seudominio.com.br | grep -i "^${HEADER}:" | tr -d '\r')
if [ -z "$VALUE" ]; then
echo "❌ AUSENTE: $HEADER"
else
echo "✅ $VALUE"
fi
done$ runstack deploy --plan starter
Não quer configurar manualmente?
Não quer configurar manualmente? Implante o VPS em menos de 3 minutos com a Runstack. Infraestrutura da OPEN DATACENTER, com servidores no Brasil.