secaudit.eu
Proteção

Cabeçalhos de segurança WordPress: CSP, HSTS e mais

Cabeçalhos de segurança WordPress explicados: valores iniciais seguros para HSTS, CSP, Referrer-Policy e Permissions-Policy, onde configurar e como evitar problemas.

Por , AngelForce OÜ 8 min de leitura

Também em: English Deutsch Français Español Italiano Polski Türkçe

Na maioria dos sites WordPress, é possível corrigir uma má classificação nos cabeçalhos em menos de uma hora. Adicione hoje quatro cabeçalhos de baixo risco: HSTS, X-Content-Type-Options, Referrer-Policy e Permissions-Policy. Depois, introduza a Content-Security-Policy com calma, começando pelo modo apenas de relatório. Este guia indica valores iniciais seguros para cada um destes cabeçalhos de segurança do WordPress, onde os configurar e quais podem estragar o editor ou os conteúdos incorporados.

O que fazem os cabeçalhos de segurança do WordPress, e o que não fazem

Os cabeçalhos de segurança são instruções que o servidor envia ao navegador do visitante. Dizem-lhe para usar apenas HTTPS, para não adivinhar tipos de ficheiro, para não deixar outros sites incorporar as suas páginas em frames e quais os scripts que pode executar. Isto reduz ataques de downgrade, MIME sniffing, clickjacking e o impacto de cross-site scripting (XSS).

Não corrigem um plugin vulnerável, não travam um ataque de tentativa de palavras-passe nem protegem o próprio servidor. Se um atacante conseguir escrever ficheiros PHP no servidor, nenhum cabeçalho ajuda. Encare-os como uma camada de reforço do lado do navegador, não como uma correção de segurança.

A falta de cabeçalhos é um exemplo clássico de configuração de segurança incorreta no OWASP Top 10. São também medidas baratas e bem documentadas, o que as torna parte do «estado da técnica» que o artigo 32.º do RGPD pede que se tenha em conta.

Diagrama: que camadas definem cabeçalhos HTTP e em que respostas
As regras do servidor e da CDN chegam a todas as respostas. Os cabeçalhos definidos por PHP podem falhar em páginas em cache e ficheiros estáticos.

A base: valores iniciais seguros para cada cabeçalho

Estes valores são propositadamente conservadores. Não devem partir um site WordPress típico e pode apertá-los mais tarde.

CabeçalhoO que fazValor inicial seguro
Strict-Transport-SecurityForça HTTPS nas visitas seguintesmax-age=300
X-Content-Type-OptionsImpede a dedução do tipo MIMEnosniff
Referrer-PolicyLimita os dados do URL enviados a outros sitesstrict-origin-when-cross-origin
Permissions-PolicyDesativa funcionalidades do navegador que não usacamera=(), microphone=(), geolocation=()
Content-Security-PolicyProteção contra frames (para já)frame-ancestors 'self'
X-Frame-OptionsProteção contra frames (legado)SAMEORIGIN

O HSTS está definido na RFC 6797. Comece com cinco minutos (max-age=300) e confirme que nada falha. Depois suba para um dia (86400), a seguir uma semana e, por fim, um ano (31536000). Só acrescente includeSubDomains depois de verificar que todos os subdomínios servem HTTPS.

Com a Referrer-Policy strict-origin-when-cross-origin, só o seu domínio é enviado a outros sites, não o URL completo. No WordPress isto conta, porque os URL levam muitas vezes parâmetros como termos de pesquisa, números de encomenda ou campanhas, e não convém que cheguem a terceiros.

A Permissions-Policy desliga a câmara, o microfone e a geolocalização nas suas páginas e em qualquer frame incorporada. Se tiver um localizador de lojas que precisa de acesso à localização, deixe geolocation fora da lista.

A proteção contra frames pertence agora à CSP, como frame-ancestors 'self'. Mantenha X-Frame-Options: SAMEORIGIN apenas como alternativa para navegadores antigos. Uma CSP pequena e ativa, com apenas frame-ancestors, pode ser aplicada já. A CSP completa vem depois.

O X-XSS-Protection está obsoleto. Não o ative. Controlava um filtro de XSS que os navegadores modernos removeram, e o próprio filtro podia ser explorado para criar novos problemas em páginas que de outra forma eram seguras. Definir 1; mode=block não traz nada. A substituta é a CSP.

Onde definir os cabeçalhos: servidor, plugin ou CDN

Escolha um único local por cabeçalho. Se o servidor, um plugin de segurança e a CDN enviarem todos Strict-Transport-Security, obtém valores duplicados ou contraditórios e ninguém sabe qual está ativo.

O servidor web costuma ser o melhor sítio. As regras do servidor aplicam-se a todas as respostas, incluindo imagens, ficheiros CSS e páginas servidas a partir de uma cache de página completa. No Apache, que cobre a maior parte do alojamento partilhado, acrescente isto ao ficheiro .htaccess na raiz do WordPress, acima do bloco # BEGIN WordPress. É necessário o mod_headers:

<IfModule mod_headers.c>
  Header always set Strict-Transport-Security "max-age=300"
  Header always set X-Content-Type-Options "nosniff"
  Header always set Referrer-Policy "strict-origin-when-cross-origin"
  Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
  Header always set Content-Security-Policy "frame-ancestors 'self'"
  Header always set X-Frame-Options "SAMEORIGIN"
</IfModule>

No nginx, coloque as linhas equivalentes no bloco server do seu site HTTPS e execute nginx -t antes de recarregar:

add_header Strict-Transport-Security "max-age=300" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "frame-ancestors 'self'" always;
add_header X-Frame-Options "SAMEORIGIN" always;

Cuidado com uma armadilha do nginx. Um bloco location que tenha a sua própria linha add_header não herda nenhuma linha add_header do nível server. Um cabeçalho de cache acrescentado para /wp-content/uploads/ pode, sem ruído, eliminar todos os seus cabeçalhos de segurança nesses ficheiros. Repita os cabeçalhos nesse bloco ou passe-os para um snippet que inclui em todo o lado com include.

Os plugins e o código que usam o hook send_headers do WordPress só atuam quando o PHP constrói a página. Os ficheiros estáticos nunca passam pelo PHP. As páginas servidas a partir de uma cache de página completa também podem dispensar o PHP, consoante a forma como a cache guarda e reproduz os cabeçalhos. As regras na CDN ou no edge são uma boa alternativa, porque cobrem tudo o que passa pela CDN. Os alojamentos geridos oferecem frequentemente definições de cabeçalhos no painel de controlo. Se o seu o fizer, use esse painel e não duplique as regras no .htaccess.

Content-Security-Policy sem partir o WordPress

A CSP é o cabeçalho com maior benefício e maior risco. Diz ao navegador que origens de scripts, estilos, imagens, tipos de letra e frames são permitidas. O WordPress complica isto. O núcleo e o editor de blocos geram scripts e estilos inline. Os page builders injetam ainda mais. Ferramentas de análise, incorporações do YouTube e de mapas, bandeiras de cookies e widgets de pagamento carregam, cada um, código de outros domínios. Uma política estrita que bloqueie qualquer um destes pode partir o checkout ou deixar o editor com o ecrã em branco.

Comece em modo apenas de relatório. O navegador regista então as violações sem bloquear nada:

Content-Security-Policy-Report-Only: default-src 'self'; img-src 'self' data:; object-src 'none'; base-uri 'self'

Abra os principais tipos de página: página inicial, um artigo, uma página com conteúdo incorporado, o carrinho e o checkout. Depois abra as ferramentas de programador do navegador e consulte a consola em cada uma. Cada violação indica o recurso bloqueado e a diretiva infringida. Trate a lista como um inventário dos pedidos a terceiros que o seu site faz. Vai encontrar muitas vezes coisas de que ninguém se lembra, como um antigo widget de chat ou tipos de letra carregados da Google. O nosso artigo sobre Google Fonts explica como lidar com isso.

Acrescente as origens de que realmente precisa, retire as restantes e volte a verificar a consola. Só mude o nome do cabeçalho para Content-Security-Policy quando as violações pararem em todas as páginas importantes. Inclua frame-ancestors 'self' nessa política completa: os navegadores ignoram frame-ancestors em modo apenas de relatório, e o cabeçalho completo vai substituir o pequeno que definiu antes. Os scripts inline são a parte difícil: permitir 'unsafe-inline' retira grande parte da proteção contra XSS, enquanto os nonces ou hashes exigem suporte do tema ou do plugin. A referência CSP da MDN documenta todas as diretivas.

Pondere deixar o wp-admin fora da política estrita, pelo menos ao início. No nginx, defina a CSP do front-end nas locations que servem o site público, em vez de no bloco server inteiro.

Pode acrescentar um endpoint report-uri ou report-to para recolher as violações de forma centralizada. Esses relatórios contêm URL de páginas e dados do navegador, e cada um chega com o endereço IP do visitante. Um serviço de relatórios de terceiros atua tipicamente como seu subcontratante ao abrigo do RGPD, pelo que precisa de um contrato de subcontratação (artigo 28.º). Num site pequeno, ler a consola por si costuma bastar.

HSTS preload: porque esperar

O preload coloca o seu domínio numa lista que os navegadores trazem de origem. Esses navegadores passam a usar HTTPS no seu domínio antes da primeira visita, e em todos os subdomínios. É aqui que está o problema. Um antigo servidor de webmail, um site de testes, a interface de uma impressora ou uma ferramenta de intranet que só funciona em HTTP simples tornam-se inacessíveis nesses navegadores.

Retirar um domínio da lista é possível, mas é lento. Os navegadores só eliminam a entrada quando a alteração chega aos utilizadores através de atualizações. Planeie como se a decisão fosse permanente.

Aumente o max-age por etapas e mantenha-o nos valores mais altos durante algum tempo. Liste todos os subdomínios que a sua organização usa, incluindo os que estão no DNS e que ninguém visita há muito. Só pondere o preload quando todos servirem HTTPS. O site de submissão hstspreload.org publica os requisitos atuais para o cabeçalho. Leia-os lá, em vez de copiar valores de artigos de blogue.

Testar os cabeçalhos e mantê-los em vigor

Verifique as respostas reais, não os ficheiros de configuração. Nas ferramentas de programador do navegador, abra o separador Rede, clique no pedido do documento e leia os cabeçalhos da resposta. A partir de um terminal:

curl -sI https://example.com/
curl -sI https://example.com/wp-includes/css/dist/block-library/style.min.css

Os sites públicos de verificação de cabeçalhos dão uma vista rápida. O OWASP Secure Headers Project explica a lógica de cada cabeçalho recomendado. Teste pelo menos estas cinco respostas:

  • Página inicial
  • Uma página servida a partir da cache, aberta sem sessão iniciada
  • Um ficheiro estático (CSS, JS ou imagem)
  • /wp-login.php
  • Um ecrã do wp-admin, incluindo o editor de blocos

Os cabeçalhos tendem a desaparecer sem que ninguém repare. As causas habituais são uma migração de alojamento que perde as regras do .htaccess, uma alteração na CDN ou um novo plugin de cache ou de segurança que envia os seus próprios valores. Volte a verificar os cabeçalhos após qualquer uma destas alterações. Guarde a configuração ativa e a data do teste junto dos restantes registos de reforço da segurança da lista de verificação de segurança. É esse registo que mostra a um questionário de cliente ou a um auditor.

O plugin de auditoria da secaudit.eu faz uma análise de reforço e configuração e associa os resultados ao artigo 32.º do RGPD e ao artigo 21.º da Diretiva NIS2. Use-o em conjunto com as verificações de cabeçalhos acima → secaudit.eu

FAQ

Os cabeçalhos de segurança afetam o SEO ou a velocidade da página?

O efeito é desprezável. Acrescentam algumas centenas de bytes a cada resposta. O HSTS pode poupar o redirecionamento de HTTP para HTTPS nas visitas repetidas.

Um plugin consegue definir todos os cabeçalhos de segurança por mim?

Em parte. Um plugin cobre as páginas geradas por PHP, mas pode falhar nos ficheiros estáticos e nas páginas em cache. As regras do servidor ou da CDN são mais fiáveis.

Devo enviar X-XSS-Protection: 0 ou omiti-lo?

Omita-o, ou envie 0 se um questionário insistir num valor explícito. O 0 desliga o filtro legado. Nunca use 1; mode=block.

O HSTS é exigido pelo RGPD?

Nenhuma regra do RGPD menciona cabeçalhos específicos. O RGPD exige, sim, segurança adequada que tenha em conta o estado da técnica. Impor HTTPS com HSTS é uma medida barata e corrente que se enquadra nessa exigência.

Este artigo é uma informação geral e não constitui aconselhamento jurídico.

Verifique o seu site

O Security Audit & Compliance é o plugin WordPress da secaudit.eu: procura malware, spam oculto, ficheiros do núcleo alterados e código vulnerável, e associa as conclusões ao art. 32.º do RGPD, ao art. 21.º da NIS2 e ao OWASP Top 10.

Ver o que o plugin verifica
Melike Görel

Melike Görel escreve os guias da secaudit.eu sobre segurança do WordPress e conformidade com as regras da UE para a AngelForce OÜ, a empresa de software de Taline responsável pela secaudit.eu.

Elaborado com apoio de IA e verificado antes da publicação. Este artigo é informação geral e não constitui aconselhamento jurídico.