SQL Injection: Do Ataque à Proteção Completa
O que é SQL Injection?
SQL Injection ocorre quando entrada de usuário é inserida diretamente em queries SQL sem sanitização. É uma das vulnerabilidades mais antigas e ainda uma das mais exploradas — responsável por incontáveis vazamentos de dados.
Como o Ataque Funciona
# Código vulnerável
def buscar_usuario(email: str):
query = f"SELECT * FROM usuarios WHERE email = '{email}'"
return db.execute(query).fetchone()Se o atacante passa como email: ' OR '1'='1
A query vira:
SELECT * FROM usuarios WHERE email = '' OR '1'='1'
-- Retorna TODOS os usuáriosOu com: '; DROP TABLE usuarios; --
SELECT * FROM usuarios WHERE email = ''; DROP TABLE usuarios; --'
-- Deleta a tabela inteiraExtração de Dados com UNION
Um ataque mais sofisticado usa UNION para extrair dados de outras tabelas:
' UNION SELECT null, table_name, null FROM information_schema.tables --Isso retorna os nomes de todas as tabelas do banco — o primeiro passo para um vazamento completo.
Proteção 1: Parâmetros Preparados (Principal Defesa)
# Python + psycopg2
cursor.execute(
"SELECT * FROM usuarios WHERE email = %s AND senha_hash = %s",
(email, senha_hash)
)
# Python + SQLAlchemy
from sqlalchemy import text
result = db.execute(
text("SELECT * FROM usuarios WHERE email = :email"),
{"email": email}
)// Node.js + pg
const result = await pool.query(
'SELECT * FROM usuarios WHERE email = $1',
[email]
);
// Node.js + mysql2
const [rows] = await conn.execute(
'SELECT * FROM usuarios WHERE email = ?',
[email]
);O banco de dados trata parâmetros como dados, nunca como SQL.
Proteção 2: ORM Correto
ORMs como Sequelize, Prisma, SQLAlchemy e Hibernate protegem automaticamente — mas apenas quando usados corretamente:
// SEGURO — Prisma usa parâmetros automaticamente
const usuario = await prisma.usuario.findUnique({
where: { email }
});
// AINDA VULNERÁVEL — raw query sem parâmetros
const usuario = await prisma.$queryRaw`SELECT * FROM usuario WHERE email = '${email}'`;
// CORRETO com raw query
const usuario = await prisma.$queryRaw`SELECT * FROM usuario WHERE email = ${email}`;
// Prisma trata ${email} como parâmetro seguro
Proteção 3: Validação de Input
from pydantic import BaseModel, EmailStr, constr
class LoginDTO(BaseModel):
email: EmailStr # valida formato de e-mail
senha: constr(min_length=8, max_length=128)
# Se a validação falhar, FastAPI retorna 422 automaticamenteProteção 4: Princípio do Menor Privilégio
O usuário do banco que a aplicação usa nunca deve ter permissões de DDL:
-- Crie um usuário específico para a aplicação
CREATE USER app_user WITH PASSWORD 'senha_forte';
-- Apenas as permissões necessárias
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_user;
-- NUNCA dê:
-- GRANT ALL PRIVILEGES ...
-- GRANT DROP, CREATE, ALTER ...Proteção 5: WAF e Detecção
Um Web Application Firewall (WAF) como AWS WAF, Cloudflare ou ModSecurity detecta padrões de SQLi:
-- Padrões suspeitos que um WAF bloqueia:
' OR 1=1
'; DROP TABLE
UNION SELECT
information_schemaConfigure alertas para tentativas — mesmo que o código esteja protegido, é importante saber que está sendo atacado.
Testando sua Aplicação
# sqlmap — ferramenta de pentest para SQLi
pip install sqlmap
sqlmap -u "https://app.com/api/usuarios?id=1" --level=3 --risk=2
# Para testar formulários
sqlmap -u "https://app.com/login" --data="email=test&senha=test" --dbsUse apenas em sistemas que você tem permissão para testar.
Checklist de Proteção
- Todas as queries usam parâmetros preparados ou ORM correto
- Nenhuma concatenação de string com input de usuário em SQL
- Usuário do banco tem permissões mínimas necessárias
- Erros SQL não são expostos ao usuário (logs internos apenas)
- WAF configurado em produção
- Testes automatizados de segurança no CI/CD
Conclusão
SQL Injection é 100% prevenível com parâmetros preparados. Não há nenhum motivo para ter essa vulnerabilidade em código novo. Use sempre ORMs ou queries parametrizadas, e nunca concatene input de usuário em SQL.