Em resumo: os security headers são instruções do servidor web ao navegador que protegem os visitantes contra ataques como Cross-Site Scripting, clickjacking e ligações não cifradas. Os mais importantes são HSTS, Content-Security-Policy, X-Content-Type-Options, proteção contra molduras alheias, Referrer-Policy e Permissions-Policy. São um reforço sensato, mas não substituem atualizações no servidor.
O que os security headers conseguem e o que não conseguem
Em cada acesso a uma página, o servidor web envia, além do conteúdo, também cabeçalhos. Alguns deles controlam funções de segurança do navegador. Assim, é possível definir, por exemplo, que uma página seja carregada apenas por HTTPS ou que o navegador não execute scripts de domínios alheios.
Para os operadores, a classificação é importante: os cabeçalhos protegem em primeiro lugar os visitantes, por exemplo contra a captura de sessões ou formulários manipulados. Não fecham vulnerabilidades no servidor. Uma fragilidade no PHP, no CMS ou numa extensão permanece, por muito bem que os cabeçalhos estejam definidos. Em conjunto com código limpo, limitam, porém, de forma clara as consequências de muitos erros.
Os security headers mais importantes em resumo
| Cabeçalho | Finalidade | Recomendação como ponto de partida |
|---|---|---|
| Strict-Transport-Security (HSTS) | impõe HTTPS nos acessos futuros | max-age=31536000; includeSubDomains |
| Content-Security-Policy (CSP) | define as fontes permitidas para scripts, imagens, molduras | individual, primeiro como Report-Only |
| X-Content-Type-Options | impede que o navegador adivinhe tipos de ficheiro | nosniff |
| X-Frame-Options ou CSP frame-ancestors | impede a incorporação em páginas alheias (clickjacking) | SAMEORIGIN ou frame-ancestors 'self' |
| Referrer-Policy | limita que endereço é transmitido a outras páginas | strict-origin-when-cross-origin |
| Permissions-Policy | desativa funções do navegador como câmara ou localização | permitir apenas as funções necessárias |
O HSTS só deve ser definido quando todos os subdomínios forem acessíveis de forma fiável por HTTPS. O navegador memoriza a instrução durante o tempo indicado; um erro não pode então ser desfeito de imediato. Comece, se necessário, com uma duração curta e aumente-a após testes bem-sucedidos. A opção adicional preload inscreve o domínio de forma permanente em listas dos fabricantes de navegadores e só deve ser definida após uma verificação cuidadosa.
Os cabeçalhos também não são o único ponto em que o navegador oferece proteção. Os cookies devem ter os atributos Secure, HttpOnly e SameSite, para que as sessões não sejam capturadas através de ligações não cifradas ou scripts. Como o configurar em PHP, descreve-o o guia sobre sessões.
Definir security headers no Nginx
No Nginx, os cabeçalhos pertencem ao bloco server do respetivo site. O acréscimo always garante que também são enviados em páginas de erro.
server {
# ...
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy-Report-Only "default-src 'self'; img-src 'self' data:; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self'" always;
server_tokens off;
}
Uma particularidade do Nginx: se um bloco location definir instruções add_header próprias, os cabeçalhos do bloco server não são aí aplicados. Verifique por isso também as subpáginas e os ficheiros estáticos. Outro reforço de segurança para esta combinação descreve-o Proteger o Nginx com PHP-FPM.
Definir security headers no Apache
No Apache, precisa do módulo mod_headers. As instruções pertencem ao VirtualHost ou, se não houver acesso a ele, ao .htaccess.
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Header always set Content-Security-Policy-Report-Only "default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"
</IfModule>
ServerTokens Prod
ServerSignature Off
ServerTokens e ServerSignature pertencem à configuração principal. Impedem que o servidor indique a sua versão exata em respostas e páginas de erro. No php.ini consegue o mesmo para o PHP com expose_php = Off.
Introduzir a Content Security Policy por fases
A Content Security Policy é o cabeçalho mais eficaz, mas também o mais exigente. Define de que fontes podem ser carregados scripts, folhas de estilo, imagens, tipos de letra e molduras. Se um script introduzido for carregado de um domínio alheio, o navegador bloqueia-o.
Os sites modernos integram muitas vezes ferramentas de análise, prestadores de pagamento, serviços de mapas ou vídeos. Uma política demasiado estrita paralisa então funções. Proceda por isso em etapas:
- Começar primeiro com
Content-Security-Policy-Report-Only. O navegador comunica as infrações na consola do programador ou para um endereço coletor, mas não bloqueia nada. - Registar todas as fontes necessárias e libertá-las de forma orientada, em vez de usar carateres universais genéricos.
- Externalizar gradualmente os scripts inline para ficheiros ou dotá-los de nonces, para que se possa prescindir de
'unsafe-inline'. - Só depois de uma fase de teste sem mensagens inesperadas passar para
Content-Security-Policy.
A CSP complementa o escaping limpo no código, mas não o substitui. Como proteger corretamente as saídas em PHP, está no guia Evitar Cross-Site Scripting em PHP.
Verificar os cabeçalhos e evitar erros típicos
Após cada alteração, deve verificar se os cabeçalhos realmente chegam. Isso faz-se sem ferramentas adicionais com curl:
# Testar a configuração e recarregar
nginx -t && systemctl reload nginx
# Mostrar os cabeçalhos da página inicial e de um ficheiro estático
curl -sI https://www.example.de/ | grep -iE 'strict|content-security|x-content|x-frame|referrer|permissions|server'
curl -sI https://www.example.de/favicon.ico | grep -iE 'strict|x-content'
Erros típicos são cabeçalhos definidos em duplicado, quando o servidor web e a aplicação enviam os mesmos cabeçalhos, um CDN intermédio que remove ou substitui cabeçalhos e cabeçalhos que aparecem só na página inicial, mas não em redirecionamentos ou páginas de erro. Verifique também, após atualizações do CMS ou de extensões de segurança, se os cabeçalhos se alteraram.
Defina por isso um único ponto em que os cabeçalhos são mantidos, de preferência o servidor web ou o serviço intermédio. Muitas extensões de CMS oferecem igualmente definições para cabeçalhos de segurança. É cómodo, mas leva facilmente a indicações duplicadas ou contraditórias, se o servidor também definir cabeçalhos. Para testes pontuais servem também as ferramentas de programador do navegador: no separador de rede vê, para cada pedido, os cabeçalhos de resposta, e a consola mostra as infrações à Content Security Policy.
Como ajuda concretamente a PHP SOS?
- Verificamos os cabeçalhos atuais de todos os seus sites, também atrás de CDN e proxy, e mostramos lacunas e contradições.
- Definimos os cabeçalhos de forma centralizada no servidor web, no âmbito do reforço de segurança do servidor, e testamos a página inicial, as subpáginas e as páginas de erro.
- Introduzimos a Content Security Policy no modo Report-Only, analisamos as mensagens e ativamo-la após acordo consigo.
- Onde as alterações ao código não são possíveis de imediato, complementamos a proteção com regras de WAF e virtual patching.
Perguntas frequentes
O que são security headers?
Os security headers são indicações adicionais na resposta do servidor web. Dizem ao navegador, por exemplo, que deve carregar a página apenas por HTTPS, não executar scripts alheios ou não mostrar a página em molduras alheias. Protegem sobretudo os visitantes.
Os security headers protegem contra o PHP2Shell?
Não. O PHP2Shell é uma vulnerabilidade no PHP do servidor; os cabeçalhos atuam no navegador do visitante. Contra o PHP2Shell ajuda a atualização para uma versão corrigida do PHP e o reinício de todos os workers. Os cabeçalhos são um reforço complementar contra outros tipos de ataque.
Uma Content Security Policy pode estragar o meu site?
Sim, uma política demasiado estrita bloqueia scripts, tipos de letra ou conteúdos incorporados necessários. Por isso, introduz-se primeiro no modo Report-Only, analisam-se as mensagens e só depois se passa à aplicação efetiva.
O X-XSS-Protection ainda faz sentido?
Não. Os navegadores atuais já não avaliam este cabeçalho, e a recomendação é omiti-lo ou defini-lo como 0. A proteção contra Cross-Site Scripting vem de um escaping limpo no código e de uma Content Security Policy.