SQL Injection (injeção de SQL) é uma falha em que dados digitados pelo usuário alteram a consulta SQL executada pelo banco. Ela permite ler, alterar e apagar dados e burlar logins. Segue como acontece e, principalmente, como evitar.
Atenção: o exemplo é só para estudo em ambiente próprio. Testar ataques em sistemas de terceiros é crime.
Código vulnerável
Um login que monta o SQL concatenando o que o usuário digitou:
<?php
$pdo = new PDO('mysql:host=127.0.0.1;dbname=loja;charset=utf8mb4', 'usuario', 'senha');
$usuario = $_POST['usuario'];
$senha = $_POST['senha'];
// VULNERÁVEL: não faça isso
$sql = "SELECT * FROM usuario WHERE usuario = '$usuario' AND senha = '$senha'";
$resultado = $pdo->query($sql);
O ataque
Se o atacante digitar no campo usuário o texto ' OR '1'='1' -- , a consulta vira:
SELECT * FROM usuario WHERE usuario = '' OR '1'='1' -- ' AND senha = ''
A condição '1'='1' é sempre verdadeira e o -- comenta o resto. O sistema retorna todos os usuários e o atacante entra sem saber a senha. Variações mais graves permitem ler outras tabelas (com UNION) ou apagar dados.
Como se proteger
1. Use consultas preparadas (prepared statements)
É a defesa principal. O SQL e os dados vão separados, e o banco nunca interpreta a entrada como código:
<?php
$stmt = $pdo->prepare('SELECT * FROM usuario WHERE usuario = :usuario');
$stmt->execute(['usuario' => $_POST['usuario']]);
$usuario = $stmt->fetch(PDO::FETCH_ASSOC);
if ($usuario && password_verify($_POST['senha'], $usuario['senha'])) {
// login válido
}
2. Não use as funções mysql_*
As antigas mysql_connect e mysql_query foram removidas do PHP 7. Use PDO ou MySQLi com consultas preparadas.
3. Valide e restrinja a entrada
Valide tipos, tamanhos e formatos (por exemplo, filter_var, (int)). Isso ajuda, mas não substitui as consultas preparadas.
4. Menor privilégio
O usuário do banco usado pela aplicação deve ter só as permissões necessárias (nunca root), limitando o dano se algo falhar.
5. Não exponha erros do banco
Mensagens de erro detalhadas ajudam o atacante. Registre-as em log e mostre ao usuário algo genérico.
6. Guarde senhas com hash
Use password_hash. Veja o tutorial de login com PHP e MySQL.
Resumo
Nunca monte SQL concatenando dados do usuário. Use consultas preparadas, o menor privilégio no banco e valide as entradas. Frameworks e ORMs modernos já fazem isso por padrão.
