Ocultar o número da versão do WordPress encaixa-se no princípio de “segurança por obscuridade”. Isoladamente, esta medida não substitui a manutenção de rotina nem a aplicação atempada de patches de segurança. No entanto, quando aliada à implementação rigorosa de cabeçalhos HTTP de segurança (Security Headers), ao encerramento de interfaces herdadas como o XML-RPC e à restrição de acessos no sistema de ficheiros, constitui uma barreira eficaz de redução de ruído e mitigação de exploração em massa.
Neste guia técnico, abordamos a fundo a engenharia de endurecimento (hardening) de uma plataforma WordPress, cobrindo o ciclo de vida dos pedidos HTTP e a configuração dos servidores web Apache e Nginx.
Como o WordPress expõe a sua versão ao público
Por omissão, uma instalação de WordPress disponibiliza pistas explícitas sobre a sua versão em várias camadas da resposta HTTP e do código-fonte HTML:
- Meta tag generator no cabeçalho HTML:
Esta etiqueta é injetada automaticamente pela ação interna<meta name="generator" content="WordPress 6.7.1" />wp_heade constitui o indicador mais comum recolhido por scanners de vulnerabilidades. - Feeds de sindicação de conteúdos (RSS, Atom, RDF): Os ficheiros de feed XML gerados em
/feed/contêm elementos dedicados como<generator>https://wordpress.org/?v=6.7.1</generator>. - Query strings em recursos estáticos (CSS e JS): Ao carregar scripts do núcleo do WordPress, como folhas de estilo do bloco Gutenberg ou ficheiros de suporte a emojis, os URLs incluem parâmetros explícitos, por exemplo
?ver=6.7.1. - Ficheiros estáticos da raiz da instalação: Ficheiros como
readme.htmloulicense.txtpermanecem frequentemente acessíveis publicamente na raiz do servidor web, revelando notas de lançamento da versão instalada.
A remoção estrutural destes elementos impede que scanners em lote associem a sua instalação a tabelas públicas de CVEs (Common Vulnerabilities and Exposures) antes mesmo de analisarem comportamentos específicos do sistema.
Hardening em PHP: Eliminação limpa de indicadores e tratamento de cache
Muitos administradores aplicam pequenos excertos de código encontrados na web que removem indiscriminadamente qualquer parâmetro ver de todas as folhas de estilo e ficheiros JavaScript. Essa prática acarreta um problema operacional grave: anula o mecanismo de cache busting do browser e das redes de distribuição de conteúdo (CDNs). Quando um tema ou plugin é atualizado, os utilizadores continuam a receber ficheiros estáticos antigos em cache porque o URL do recurso não mudou.
A abordagem de engenharia correta consiste em remover apenas os valores que correspondem à versão principal do núcleo do WordPress, preservando versões personalizadas e hashes de ficheiros de terceiros.
Remoção de etiquetas generator e feeds
A forma mais limpa e manutenível de aplicar estas regras é através de um Must-Use Plugin (wp-content/mu-plugins/security-hardening.php), garantindo que a execução não depende do tema ativo:
<?php
/**
* Plugin Name: Hardening de Reconhecimento WordPress
* Description: Remove a identificação pública da versão do núcleo nos cabeçalhos HTML e feeds.
*/
// 1. Remover a meta tag generator do HTML head
remove_action('wp_head', 'wp_generator');
// 2. Remover identificadores de versão em feeds RSS e Atom
remove_action('rss_head', 'the_generator');
remove_action('rss2_head', 'the_generator');
remove_action('commentsrss2_head', 'the_generator');
remove_action('atom_head', 'the_generator');
remove_action('rdf_header', 'the_generator');
remove_action('opml_head', 'the_generator');
// 3. Limpar saídas textuais do filtro the_generator
add_filter('the_generator', '__return_empty_string');Filtragem seletiva de versões em scripts e estilos
Para tratar os URLs dos ficheiros estáticos sem prejudicar as políticas de cache dos plugins, implementamos um filtro que valida se o argumento ver é idêntico à variável global $wp_version:
function wppoland_remover_versao_core_assets(string $src): string {
global $wp_version;
if (empty($src)) {
return $src;
}
$url_decomposta = parse_url($src);
if (!isset($url_decomposta['query'])) {
return $src;
}
parse_str($url_decomposta['query'], $parametros);
// Remove apenas se o valor da query string for exatamente a versão do núcleo
if (isset($parametros['ver']) && $parametros['ver'] === $wp_version) {
return remove_query_arg('ver', $src);
}
return $src;
}
add_filter('style_loader_src', 'wppoland_remover_versao_core_assets', 9999);
add_filter('script_loader_src', 'wppoland_remover_versao_core_assets', 9999);Com este filtro ativo, os ficheiros nativos do WordPress perdem a referência pública de versão, enquanto scripts com versões semânticas independentes continuam a beneficiar de invalidação atempada de cache no browser do utilizador.
Arquitetura de cabeçalhos HTTP de segurança (Security Headers)
Os cabeçalhos HTTP de segurança são diretivas enviadas pelo servidor que instruem os navegadores modernos sobre como lidar com o isolamento de recursos, prevenção de carregamento em molduras externas e políticas de execução de scripts.
A configuração direta no servidor web (Apache ou Nginx) é altamente preferível à execução via PHP, uma vez que servidores proxy reversos e sistemas de cache em página inteira (Full Page Cache) entregam respostas estáticas sem invocar o motor PHP.
1. X-Content-Type-Options: nosniff
Impede que o navegador tente adivinhar o tipo MIME de um ficheiro quando este difere do cabeçalho Content-Type declarado pelo servidor. Isso anula ataques onde um invasor carrega uma imagem contendo código JavaScript oculto e induz o navegador a executá-la.
Header always set X-Content-Type-Options "nosniff"2. X-Frame-Options: SAMEORIGIN
Protege a aplicação contra ataques de Clickjacking. Se esta diretiva não estiver presente, uma página web maliciosa externa pode incorporar o painel administrativo ou o formulário de checkout da sua loja num elemento <iframe> invisível, induzindo o utilizador autenticado a executar ações destrutivas.
Header always set X-Frame-Options "SAMEORIGIN"3. HTTP strict transport security (HSTS)
O HSTS força o browser a comunicar exclusivamente através do protocolo HTTPS, eliminando tentativas de downgrade para HTTP inseguro em redes públicas ou ataques de Man-in-the-Middle (MitM).
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"O parâmetro max-age=31536000 define a validade da política por um período de um ano civil (em segundos).
4. Referrer-Policy: strict-origin-when-cross-origin
Regula a quantidade de dados de encaminhamento (Referer) transmitidos para websites externos quando os visitantes clicam em hiperligações. Esta política envia o caminho completo em pedidos internos seguros, mas reduz os dados apenas ao nome de domínio de origem em pedidos entre domínios diferentes sob HTTPS.
Header always set Referrer-Policy "strict-origin-when-cross-origin"5. Permissions-Policy
Permite desativar recursos do hardware do cliente (como câmara, microfone ou geolocalização) que o seu website institucional ou de comércio eletrónico não utiliza. Se uma biblioteca de terceiros for comprometida, o navegador bloqueia qualquer tentativa de ativação desses sensores.
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()"6. Content-Security-Policy (CSP)
A Content Security Policy é a salvaguarda mais robusta contra ataques de Cross-Site Scripting (XSS). Ao declarar expressamente os domínios autorizados a servir scripts, estilos, fontes e conexões assíncronas, inviabiliza a execução de código arbitrário injetado na base de dados.
Um exemplo prático e equilibrado para sites WordPress com Google Analytics e bibliotecas externas autorizadas:
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.google-analytics.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data: https:; connect-src 'self' https://www.google-analytics.com; frame-ancestors 'self';"Configurações completas para servidores Apache e Nginx
Abaixo encontram-se exemplos prontos para utilização nos ambientes de alojamento mais comuns.
Configuração Apache (.htaccess)
Coloque estas regras no topo do seu ficheiro .htaccess, antes do bloco padrão # BEGIN WordPress:
# --- WPPoland Hardening de Cabeçalhos HTTP ---
<IfModule mod_headers.c>
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Header always set X-XSS-Protection "1; mode=block"
</IfModule>
# Bloquear ficheiros de documentação e ficheiros sensíveis
<FilesMatch "^(wp-config\.php|readme\.html|license\.txt|\.env)">
Require all denied
</FilesMatch>
# Desativar acesso direto ao XML-RPC
<Files xmlrpc.php>
Require all denied
</Files>Configuração Nginx (server block)
No Nginx, declare os cabeçalhos dentro do bloco de servidor principal correspondente a HTTPS:
server {
listen 443 ssl http2;
server_name exemplo.pt www.exemplo.pt;
ssl_certificate /etc/letsencrypt/live/exemplo.pt/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/exemplo.pt/privkey.pem;
# Cabeçalhos de Segurança
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
# Ocultar versão do servidor Nginx
server_tokens off;
root /var/www/exemplo.pt;
index index.php index.html;
# Bloqueio de ficheiros do núcleo informativos
location ~* /(?:readme\.html|license\.txt|wp-config\.php) {
deny all;
}
# Bloqueio total a pedidos XML-RPC
location = /xmlrpc.php {
deny all;
access_log off;
log_not_found off;
}
# Processamento PHP FastCGI
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
}Fechar superfícies de ataque: XML-RPC e Enumeração de Utilizadores
A robustez de um sistema WordPress passa pela redução deliberada da superfície exposta. Existem dois vetores clássicos de recolha de credenciais que devem ser neutralizados em qualquer instalação corporativa:
Bloqueio do ficheiro xmlrpc.php
O protocolo XML-RPC foi projetado para comunicações remotas antes da estabilização da REST API moderna. Atualmente, representa um risco operacional grave devido ao método system.multicall. Com uma única requisição HTTP POST contendo um payload XML estruturado, um invasor pode submeter centenas de tentativas de autenticação combinadas, contornando plugins convencionais de limitação de tentativas de login.
A menos que utilize aplicações legadas como o módulo de publicação remota do Jetpack ou a aplicação móvel original do WordPress, deve desativar categoricamente o acesso ao ficheiro xmlrpc.php ao nível do servidor web (como demonstrado nas configurações acima).
Prevenção de enumeração de utilizadores na REST API
Por padrão, a interface REST do WordPress expõe o endpoint público /wp-json/wp/v2/users, que lista os autores de artigos com respetivos slugs de utilizador (nomes de conta no login). Isso permite a bots mapear os nomes de utilizador antes de iniciarem ataques de força bruta no ecrã de acesso.
Para mitigar este vetor, intercete os endpoints da API para utilizadores não autorizados:
add_filter('rest_endpoints', function(array $endpoints): array {
if (isset($endpoints['/wp/v2/users']) && !current_user_can('list_users')) {
unset($endpoints['/wp/v2/users']);
}
if (isset($endpoints['/wp/v2/users/(?P<id>[\d]+)']) && !current_user_can('list_users')) {
unset($endpoints['/wp/v2/users/(?P<id>[\d]+)']);
}
return $endpoints;
});Adicionalmente, intercete o parâmetro arcaico de consulta de autores por ID via URL (/?author=1), redirecionando-o para a página inicial:
add_action('template_redirect', function(): void {
if (is_author() && !is_admin()) {
wp_safe_redirect(home_url(), 301);
exit;
}
});Permissões de ficheiros e diretórios no Linux
Mesmo com cabeçalhos fortes, o isolamento a nível do sistema operacional é a barreira final de contenção caso uma vulnerabilidade em algum plugin permita o envio de ficheiros maliciosos.
As diretrizes oficiais de administração recomendam uma segregação estrita entre permissões de leitura, escrita e execução:
# Definir todas as diretorias para 755 (rwxr-xr-x)
find /var/www/exemplo.pt/ -type d -exec chmod 755 {} \;
# Definir todos os ficheiros comuns para 644 (rw-r--r--)
find /var/www/exemplo.pt/ -type f -exec chmod 644 {} \;
# Restringir o ficheiro de configuração com credenciais da base de dados
chmod 400 /var/www/exemplo.pt/wp-config.phpSob esta configuração, o processo do servidor web (www-data ou utilizador do pool PHP-FPM) não dispõe de permissões de escrita direta sobre os ficheiros PHP principais, com exceção da pasta wp-content/uploads/ destinada ao carregamento de ficheiros multimédia.
Bloqueio da edição de código no painel de controlo
Para evitar que invasores com credenciais administrativas alterem temas ou plugins através do editor integrado do WordPress, adicione a seguinte constante ao ficheiro wp-config.php:
define('DISALLOW_FILE_EDIT', true);Esta instrução remove totalmente o submenu de edição de ficheiros do painel administrativo, eliminando uma via crítica de persistência de código malicioso.
Validação prática das implementações
Após aplicar as configurações no código e nos servidores, valide o comportamento real através do terminal:
- Inspeção de cabeçalhos HTTP com cURL:
curl -sI https://exemplo.pt | grep -iE "(strict-transport|x-frame|x-content|permissions|x-xss)" - Verificação de ausência da tag generator:
curl -s https://exemplo.pt | grep -i "generator" - Auditorias automatizadas: Submeta o domínio em serviços como o SecurityHeaders.com para aferir a pontuação global e confirmar a conformidade das diretivas declaradas.
Perguntas Frequentes (FAQ)
Esconder a versão do WordPress torna o website seguro?
A remoção de query strings quebra o carregamento de CSS e JS?
É seguro desativar totalmente o XML-RPC?
Qual o impacto da Content Security Policy nos temas?
Conclusão
O endurecimento da infraestrutura do WordPress é uma disciplina contínua que combina boas práticas de desenvolvimento em PHP e rigor técnico na administração de sistemas. Ao eliminar os vestígios da versão do CMS e estabelecer uma defesa sólida com cabeçalhos de segurança e permissões de ficheiros restritivas, protege o seu negócio contra ataques oportunistas e ameaças automatizadas.
Para uma avaliação exaustiva dos vetores de risco da sua plataforma digital, consulte os nossos serviços de auditoria de segurança WordPress ou conte com o suporte técnico dos nossos especialistas WordPress.







