Injeção SQL em PHP: como se proteger em 2025

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: por que as injeções SQL ainda são relevantes?

\n\n

Imagine: seu site funciona perfeitamente, usuários se registram, deixam comentários, fazem pedidos. De repente — o banco de dados cai nas mãos de um invasor. Não porque os hackers são gênios, mas porque alguém esqueceu de colocar um ponto de interrogação em uma consulta SQL.

\n\n

Injeções SQL não são uma ameaça arcaica dos anos 2000. Em 2024, a OWASP ainda as coloca entre as 3 vulnerabilidades mais perigosas em aplicações web. E a pergunta "How can I prevent SQL injection in PHP?" no Stack Overflow já ultrapassou 1,5 milhão de visualizações — e continua crescendo. Ou seja, o problema está vivo.

\n\n

Neste artigo, vamos entender como fechar a porta para injeções SQL em PHP em 2025 de forma definitiva. Sem mágica, sem frameworks complexos, apenas código limpo e melhores práticas.

\n\n

O que é injeção SQL em termos simples?

\n\n

Injeção SQL é quando a entrada do usuário se torna parte do comando SQL, e não apenas dados. Exemplo prático:

\n\n
<?php\n// CÓDIGO RUIM — nunca faça isso!\n$username = $_POST['username'];\n$query = "SELECT * FROM users WHERE username = '$username'";\n$result = mysqli_query($conn, $query);\n?>
\n\n

Se um invasor digitar no campo username a string ' OR '1'='1, a consulta se torna:

\n\n
SELECT * FROM users WHERE username = '' OR '1'='1'
\n\n

Isso retorna todos os usuários. E se digitar '; DROP TABLE users; -- — você pode perder toda a tabela. Assustador? Com certeza.

\n\n

Melhores práticas de proteção contra injeções SQL em PHP 2025

\n\n

1. Use PDO com consultas preparadas (é o padrão)

\n\n

PDO (PHP Data Objects) é uma interface universal para trabalhar com bancos de dados. Sua principal vantagem: ele separa a lógica SQL dos dados. Você escreve a consulta com placeholders, e o PDO cuida da sanitização segura.

\n\n
<?php\n// CÓDIGO BOM — use PDO\n$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8mb4';\n$pdo = new PDO($dsn, $user, $pass, [\n    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,\n    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,\n    PDO::ATTR_EMULATE_PREPARES => false, // desativa emulação\n]);\n\n$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');\n$stmt->execute(['email' => $_POST['email']]);\n$user = $stmt->fetch();\n?>
\n\n

Por que isso funciona? O banco de dados recebe a estrutura da consulta separada dos dados. Mesmo que o usuário insira SQL malicioso, ele será interpretado como uma string comum, não como parte do comando.

\n\n

2. Mysqli com consultas preparadas (alternativa)

\n\n

Se você trabalha apenas com MySQL, pode usar mysqli — mas apenas com consultas preparadas, não com sanitização via mysqli_real_escape_string().

\n\n
<?php\n$mysqli = new mysqli('localhost', 'user', 'pass', 'testdb');\n$stmt = $mysqli->prepare('INSERT INTO comments (user_id, text) VALUES (?, ?)');\n$stmt->bind_param('is', $userId, $commentText);\n$stmt->execute();\n?>
\n\n

Importante: em 2025, mysqli_real_escape_string() ainda existe, mas confiar nele para proteção é uma má ideia. Ele sanitiza apenas strings, mas não protege contra injeções em campos numéricos ou operadores LIKE.

\n\n

3. Filtragem e validação — segunda linha de defesa

\n\n

Consultas preparadas são a base. Mas adicione filtragem por tipo de dado. Se espera um número — verifique se é um número. Se espera um email — verifique o formato.

\n\n
<?php\n$id = filter_input(INPUT_POST, 'user_id', FILTER_VALIDATE_INT);\nif ($id === false) {\n    throw new InvalidArgumentException('ID deve ser um inteiro');\n}\n\n$stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');\n$stmt->execute(['id' => $id]);\n?>
\n\n

Combinar

Blogs

Book Recommendations