SQL Injection é uma das falhas mais exploradas na web. Ela permite que invasores manipulem consultas SQL e acessem dados sigilosos. A boa notícia: é 100% evitável com práticas corretas. Nesse artigo você verá:
- O que é SQL Injection e como acontece
- Erros comuns em WordPress e PHP
- Entrada segura: validação e saneamento
- Prepared Statements no WordPress
- Prepared Statements em PHP (PDO/MySQLi)
- Hardening no servidor e no banco
- Como detectar e responder a incidentes
- Checklist rápido de prevenção
- FAQ e tags de referência
1) O que é SQL Injection e como acontece
O ataque ocorre quando dados do usuário entram na query sem preparo. O atacante injeta comandos e altera o resultado. O impacto vai de vazamento a exclusão total do banco.
2) Erros comuns em WordPress e PHP
- Concatenar variáveis diretamente na SQL. Evite sempre.
- Confiar apenas em
esc_sql(). Ela não substitui prepare. - Falta de nonce e checagem de capabilities em AJAX/REST.
- Campos numéricos tratados como texto. Tipagem importa.
3) Entrada segura: validação e saneamento
- Valide por whitelist (valores permitidos). É mais seguro.
- Tipagem: use
absint(),intval(),floatval(). - Strings:
sanitize_text_field()esanitize_email(). - Arquitetura: valide no backend mesmo que o frontend valide.
4) Prepared Statements no WordPress
Use $wpdb->prepare() para toda SQL dinâmica. A engine faz o escape correto por tipo.
4.1) SELECT seguro
// Exemplo seguro com $wpdb->prepare()
global $wpdb;
$post_id = absint($_GET['id'] ?? 0);
$sql = $wpdb->prepare(
"SELECT meta_value FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key = %s",
$post_id,
'_minha_chave'
);
$valor = $wpdb->get_var($sql);
4.2) INSERT/UPDATE seguros
global $wpdb;
$dados = [
'user_id' => get_current_user_id(),
'comentario'=> sanitize_text_field($_POST['comentario'] ?? '')
];
$format = ['%d','%s'];
$wpdb->insert("{$wpdb->prefix}comentarios", $dados, $format);
// UPDATE
$wpdb->update(
"{$wpdb->prefix}comentarios",
['comentario' => $dados['comentario']],
['user_id' => $dados['user_id']],
['%s'], ['%d']
);
4.3) NUNCA faça assim
// Vulnerável. Não concatene entrada do usuário.
$busca = $_GET['q'] ?? '';
$sql = "SELECT * FROM {$wpdb->posts} WHERE post_title LIKE '%$busca%'";
$linhas = $wpdb->get_results($sql);
5) Prepared Statements em PHP (PDO/MySQLi)
5.1) PDO
$pdo = new PDO($dsn, $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false
]);
$stmt = $pdo->prepare("SELECT * FROM clientes WHERE email = :email AND status = :status");
$stmt->execute([
':email' => filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL),
':status' => 'ativo'
]);
$cliente = $stmt->fetch(PDO::FETCH_ASSOC);
5.2) MySQLi
$mysqli = new mysqli($host, $user, $pass, $db);
$stmt = $mysqli->prepare("SELECT id, nome FROM pedidos WHERE id = ?");
$id = (int)($_GET['id'] ?? 0);
$stmt->bind_param("i", $id);
$stmt->execute();
$result = $stmt->get_result();
6) Hardening no servidor e no banco
- Princípio do menor privilégio: o usuário do banco só precisa de grants mínimos.
- Desative exibição de erros em produção. Logue em arquivo seguro.
- Ative WAF e regras anti‑injection. ModSecurity, Cloudflare/WAF e firewall de aplicação ajudam.
- Bloqueie execução PHP em
/uploads. Separe credenciais por ambiente. - Rotacione senhas e use variáveis de ambiente (
wp-config.phplimpo).
7) Como detectar e responder a incidentes
- Monitore logs de acesso e de queries lentas. Padrões de
' OR '1'='1são suspeitos. - Audite endpoints
admin-ajax.phpe REST personalizados. Cheque nonce e capabilities. - Reveja alterações recentes no repositório/deploy. Busque concatenações em SQL.
- Ao confirmar o incidente: isole o site, troque credenciais e aplique patch imediato.
8) Checklist rápido de prevenção
- Usa
prepare()em toda query dinâmica. - Valida e tipa entradas no backend.
- Nonce +
current_user_can()em AJAX/REST. - Usuário do banco com privilégios mínimos.
- Erros ocultos e logs ativos.
- WAF e bloqueio de PHP no
/uploads. - Revisão de código antes de cada release.
Perguntas Frequentes (FAQ)
O que é SQL Injection?
É a inserção de comandos SQL maliciosos em entradas do sistema. O objetivo é manipular ou ler dados sem permissão.esc_sql() resolve o problema?
Não sozinho. Use $wpdb->prepare(). Ela garante o tipo e a posição corretos dos parâmetros.Preciso validar dados mesmo usando prepare?
Sim. Prepare previne injeção, não regra de negócio. Valide tipos, formatos e limites.Como proteger AJAX e REST no WordPress?
Exija nonce válido e verifique current_user_can(). Aplique prepare() em queries internas.WAF substitui prepared statements?
Não. WAF é camada extra. Prepared statements são obrigatórios na aplicação.
Tags
WordPress, Segurança, SQL Injection, Prepared Statements, $wpdb, PDO, MySQLi, WAF, Hardening, Server Express









