Evitando SQL injection: as 5 práticas essenciais para devs WordPress
Em 2026, os ataques de SQL injection continuam sendo uma das principais causas de invasão em sites WordPress. E o motivo quase sempre é o mesmo: código mal escrito que permite a um atacante manipular consultas ao banco de dados. Se você desenvolve plugins, temas ou qualquer funcionalidade personalizada, conhecer e aplicar as práticas corretas para evitar SQL injection não é opcional – é obrigação. Este guia mostra as 5 práticas essenciais que todo dev WordPress deve dominar.
O que é SQL injection (na prática)
Imagine que você tem uma consulta que busca um usuário pelo ID passado na URL:
$user_id = $_GET['id'];
$query = "SELECT * FROM wp_users WHERE ID = $user_id";
$results = $wpdb->get_results($query);Um atacante pode enviar algo como: ?id=1 OR 1=1; DROP TABLE wp_users; --. O resultado: a query se torna SELECT * FROM wp_users WHERE ID = 1 OR 1=1; DROP TABLE wp_users; -- – todos os usuários são retornados e a tabela é deletada. Simples, devastador, e infelizmente comum.
As 5 práticas essenciais
A função prepare() da classe $wpdb é a primeira linha de defesa. Ela escapa automaticamente os valores, garantindo que qualquer dado fornecido pelo usuário seja tratado como valor, não como parte da sintaxe SQL.
// ❌ ERRADO
$user_id = $_GET['id'];
$query = "SELECT * FROM wp_users WHERE ID = $user_id";
$user = $wpdb->get_row($query);
// ✅ CORRETO
$user_id = absint($_GET['id']);
$query = $wpdb->prepare("SELECT * FROM wp_users WHERE ID = %d", $user_id);
$user = $wpdb->get_row($query);Placeholders: %s para string, %d para inteiro, %f para float. Nunca concatene variáveis diretamente na string SQL.
Para tarefas comuns (buscar um campo, contar registros), o $wpdb já oferece métodos que internamente tratam os dados. Além disso, sempre que possível, evite escrever SQL manual e use as funções de alto nível (ex: WP_Query, get_metadata, get_terms).
// ✅ Recomendado (abstração segura)
$user = get_user_by('id', $user_id);
// ✅ Alternativa com $wpdb (ainda segura)
$user = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->users WHERE ID = %d", $user_id));
Antes mesmo de construir a query, certifique-se de que o dado está no formato esperado. Use funções do WordPress:
absint()– converte para inteiro positivosanitize_text_field()– limpa strings básicassanitize_email()– valida e-mailsanitize_key()– para slugs e chaves alfanuméricasesc_sql()– escape para SQL (mas prefira prepare)
$user_id = isset($_GET['id']) ? absint($_GET['id']) : 0;
if ($user_id === 0) {
wp_die('ID inválido');
}Nunca confie em dados vindos de $_GET, $_POST, $_COOKIE, $_SERVER ou até do banco de dados (se o banco já foi comprometido).
SQL injection muitas vezes é combinado com falhas de autorização. Mesmo que um atacante consiga injetar SQL, se a rota que ele está atacando exigir uma capacidade específica (ex: manage_options) ou um nonce válido, o dano pode ser mitigado.
// Verifica se o usuário atual pode editar posts
if (!current_user_can('edit_posts')) {
wp_die('Acesso negado');
}
// Verifica nonce para ações via POST
if (!wp_verify_nonce($_POST['nonce'], 'meu_plugin_action')) {
wp_die('Nonce inválido');
}Isso não substitui a sanitização, mas adiciona uma camada extra de segurança.
Consultas com LIKE são particularmente problemáticas porque caracteres curinga (% e _) precisam ser escapados. O WordPress oferece esc_like() para isso.
$search = '%' . $wpdb->esc_like($user_input) . '%';
$query = $wpdb->prepare("SELECT * FROM $wpdb->posts WHERE post_title LIKE %s", $search);
$results = $wpdb->get_results($query);Não tente escapar manualmente com addslashes ou str_replace – sempre use as funções nativas.
esc_sql() existe, mas é considerada obsoleta para prepared statements. Use $wpdb->prepare() sempre que possível. esc_sql() só deve ser usado em casos muito específicos (ex: nomes de tabelas dinâmicos).Exemplo prático: formulário de busca vulnerável vs. seguro
Código vulnerável (NUNCA use):
$search = $_POST['search'];
$query = "SELECT * FROM wp_posts WHERE post_title LIKE '%$search%'";
$results = $wpdb->get_results($query);Código seguro (use assim):
$search = sanitize_text_field($_POST['search']);
$search_like = '%' . $wpdb->esc_like($search) . '%';
$query = $wpdb->prepare("SELECT * FROM $wpdb->posts WHERE post_title LIKE %s", $search_like);
$results = $wpdb->get_results($query);
Ferramentas para detectar SQL injection no seu código
- Query Monitor – mostra todas as queries executadas. Verifique se alguma está concatenando variáveis diretamente.
- PHPStan com extensão WordPress – análise estática que detecta uso incorreto de
$wpdb. - Semgrep – regras personalizadas para buscar padrões de concatenação em SQL.
- WordPress Coding Standards (PHPCS) – as regras
WordPress.DB.PreparedSQLeWordPress.DB.DirectDatabaseQueryapontam más práticas.
E se você está usando WP_Query ou funções de alto nível?
Ótimo! Funções como WP_Query, get_posts, get_metadata, get_terms já sanitizam os parâmetros internamente. Por exemplo:
$args = [
's' => $_GET['s'], // busca por texto livre
'post_type' => 'post',
];
$query = new WP_Query($args);Mesmo assim, sanitize os parâmetros antes de passar para o array, especialmente 's' (busca) e 'meta_query' valores.
$wpdb->prefix ao invés de wp_ fixo no nome das tabelas. Permite que o site use prefixos personalizados e evita SQL injection na parte do nome da tabela.O que fazer se seu site foi atacado?
- Isole o site (modo manutenção ou bloqueio por IP).
- Restaure backup limpo (anterior ao ataque).
- Verifique logs de acesso e de erros (seu servidor e o debug.log do WordPress).
- Instale um firewall de aplicação (WAF) temporariamente.
- Audite todos os plugins e temas customizados em busca de SQL injection (use as ferramentas citadas).
- Altere todas as senhas (admin, FTP, banco de dados).
- Após corrigir, remova o WAF e reative o site.
Em caso de invasão confirmada, considere contratar um especialista em segurança para limpeza profunda.

Conclusão: segurança é processo, não produto
Aplicar as 5 práticas acima reduz drasticamente o risco de SQL injection no WordPress. Mas lembre-se: a segurança nunca é definitiva. Mantenha-se atualizado sobre novas vulnerabilidades, use plugins de segurança (ex: Wordfence, Sucuri) e sempre revise seu código ou o de terceiros.
Resumo rápido:
- ✅ Sempre use
$wpdb->prepare()com placeholders. - ✅ Sanitize e valide todos os inputs externos.
- ✅ Para consultas LIKE, use
esc_like()antes deprepare(). - ✅ Prefira funções de alto nível (
WP_Query,get_user_by). - ✅ Adicione nonces e verificações de capacidade.
🔒 Quer mais segurança para seus projetos?
Na nossa loja você encontra plugins de firewall, scanners de vulnerabilidade e temas com código auditado. Não deixe a segurança do seu site para depois.
🛒 Explorar catálogo de segurança →Ainda com dúvidas sobre como proteger seu código? Continue nos acompanhando! Publicaremos mais conteúdo sobre segurança no WordPress.
Você já sofreu ou encontrou SQL injection em algum projeto? Compartilhe sua experiência com outros profissionais e vamos fortalecer a segurança da comunidade WordPress.


