Programação

SQL Injection: exemplo prático com PHP + MySQL

SQL Injection em PHP e MySQL: veja um exemplo prático de código vulnerável, como o ataque funciona e como se proteger com prepared statements.

Capa: SQL Injection: exemplo prático com PHP + MySQL

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.

Mais artigos