Como proteger seu banco de dados contra SQL Injection

O que é SQL Injection (definição curta)
SQL Injection é uma técnica de ataque em que comandos SQL maliciosos são inseridos em entradas de uma aplicação para manipular a consulta executada no banco de dados. Em uma linha: é tratar dados do usuário como código.
Por que isso é perigoso
- Pode devolver dados sensíveis (ex.: credenciais, PII).
- Pode modificar ou apagar tabelas inteiras.
- Pode permitir elevação de privilégios ou execução remota em alguns cenários.
Importante: ataques funcionam apenas quando a aplicação constrói consultas SQL concatenando diretamente dados não confiáveis.
Como um ataque típico acontece
Um formulário de login que monta uma string SQL com os valores enviados pelo usuário é um alvo clássico. Exemplo vulnerável em PHP (não use em produção):
Se um atacante enviar ' OR 'a'='a
no campo de senha, a condição se tornará sempre verdadeira e o acesso pode ser concedido sem credenciais válidas.
Principais vetores e variações
- Error-based: o atacante força o banco a retornar mensagens de erro detalhadas para descobrir a estrutura do banco.
- Union-based: usa UNION para combinar resultados e exfiltrar dados.
- Blind SQL Injection: o atacante não recebe resultados diretos, mas infere dados por testes booleanos ou temporizadores.
- Out-of-band: usa canais externos (DNS, HTTP) para extrair dados.
Estratégias de defesa (camadas)
A proteção eficaz usa várias camadas. Nenhuma técnica isolada é 100% segura.
1) Consultas parametrizadas (prepared statements) — prioridade
Prepared statements separam o código SQL dos dados do usuário. Use sempre que possível.
Exemplo com PDO (PHP) — recomendado:
prepare('SELECT * FROM users WHERE username = :username AND user_password = :password');
$stmt->execute([':username' => $_POST['username'], ':password' => $_POST['password']]);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
Exemplo com MySQLi (PHP):
prepare('SELECT * FROM users WHERE username = ? AND user_password = ?');
$stmt->bind_param('ss', $_POST['username'], $_POST['password']);
$stmt->execute();
$result = $stmt->get_result();
?>
Exemplo em Python com psycopg2 (Postgres):
cur.execute('SELECT * FROM users WHERE username = %s AND user_password = %s', (username, password))
Observação: prepared statements tratam entradas como dados, não como parte do SQL, eliminando a maior parte das injeções.
2) Validação e sanitização de entradas
- Validação: verifique tipo, tamanho, formato (whitelisting preferível). Ex.: e-mail deve corresponder a regex básica, IDs devem ser inteiros.
- Sanitização: remova espaços em excesso, caracteres de controle, quebras de linha. Use com cautela — nunca confie só em escaping.
- Evite construir SQL concatenando strings com dados do usuário.
Exemplo de validação simples em PHP:
if (!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
// rejeitar entrada
}
$id = intval($_GET['id']); // força número inteiro
3) Escaping (quando necessário)
Escaping (ex.: mysqli_real_escape_string) pode reduzir risco, mas não substitui prepared statements. Útil em contexts legados onde prepared statements não são possíveis.
4) Princípio do menor privilégio (least privilege)
- Cada aplicação/serviço deve usar uma conta de banco de dados com apenas os direitos necessários (SELECT, INSERT, UPDATE específicos), não a conta SA/root.
- Separe contas para leitura e escrita quando aplicável.
Exemplo (Microsoft SQL Server):
deny select on sys.tables to sqldatabasepermit;
deny select on sys.packages to sqldatabasepermit;
deny select on sys.sysobjects to sqldatabasepermit;
5) Trate erros com cuidado
Não exponha mensagens de erro detalhadas ao usuário final — registros internos podem conter detalhes úteis para depuração, mas devem ser protegidos.
6) Camadas adicionais
- ORM (Object-Relational Mapping): frameworks bem projetados reduzem risco ao gerar consultas seguras, mas verifique pontos onde consultas brutas são usadas.
- Stored procedures: podem ajudar se parametrizadas corretamente; não use procedures que concatenam strings SQL internamente.
- Web Application Firewall (WAF): filtro adicional para detectar padrões de ataque.
Arquiteturas, heurísticas e mental models
- Mental model: pense em dados como toxina — sempre contenha-os com barreiras (validação, parametrização, privilégios mínimos).
- Heurística: “Never trust user input” — trate tudo como hostil até provar o contrário.
Checklist rápido para desenvolvedores e DBAs
- Todas as consultas que usam dados externos usam prepared statements.
- Campos são validados por tipo, tamanho e formato (whitelist).
- Contas de banco seguem princípio do menor privilégio.
- Mensagens de erro amigáveis ao usuário; logs detalhados internos e protegidos.
- Revisões de código e testes automatizados para injeção.
- Monitoramento e alertas para atividades anômalas (padrões de consulta, longos tempos de execução).
Playbook de resposta a incidente (resumo)
- Isolar a aplicação/endpoint afetado.
- Reverter a partir de backup conhecido e limpo se houver corrupção de dados.
- Rodar análise forense: logs de aplicação, logs do banco, conexões recentes.
- Bloquear credenciais ou rotacionar chaves afetadas.
- Aplicar correções (ex.: converter consultas vulneráveis para prepared statements).
- Notificar stakeholders e, se aplicável, cumprir obrigações regulatórias.
Importante: mantenha backups imutáveis e registre táteis (audit logs) para investigação.
Quando as defesas podem falhar (contraexemplos)
- Aplicação usa ORM mas permite SQL bruto concatenado em algumas rotas — risco persiste.
- Prepared statements são usados, mas entradas usadas em cláusulas dinâmicas (ORDER BY, table names) são concatenadas sem validação.
- Erros de configuração: conta do app tem privilégios elevados por erro operacional.
Testes e aceitação
Critérios de aceitação:
- Todas as rotas que aceitam input externo passam em testes automatizados de injeção (SAST/DAST + fuzzing).
- Sem mensagens de erro SQL detalhadas para usuários.
- Contas com privilégios restringidos documentadas.
Casos de teste recomendados:
- Teste booleano: injetar
' OR '1'='1
e garantir que não retorna dados indevidos. - Teste de union: injetar payloads com UNION e verificar bloqueio/nenhum dado sensível retornado.
- Teste de tempo (blind): injetar operações que dormem (quando aplicável) e checar comportamento.
Maturidade: níveis rápidos
- Nível 1 (Inicial): consultas concatenadas, pouca ou nenhuma validação.
- Nível 2 (Intermediário): validação básica, alguns prepared statements, logs básicos.
- Nível 3 (Maduro): prepared statements em toda a entrada, least privilege, WAF, testes automáticos SAST/DAST, resposta a incidente definida.
Perguntas frequentes (FAQ)
O escaping é suficiente para prevenir SQL injection?
Escaping reduz risco, mas não é tão robusto quanto prepared statements. Use escaping apenas em contextos legados; migre para prepared statements.
ORM elimina a necessidade de validar entradas?
Não. ORM ajuda, mas validação continua necessária para dados semânticos (ex.: tamanhos, formatos) e para evitar construção de SQL dinâmico inseguro.
Devo bloquear mensagens de erro do banco de dados?
Sim: mostre mensagens genéricas ao usuário e registre detalhes sensíveis em logs internos com acesso restrito.
Resumo final
SQL Injection continua sendo uma das ameaças mais comuns a aplicações que usam bancos relacionais. A defesa eficaz combina práticas de desenvolvimento seguro (prepared statements, validação por whitelist), arquitetura segura (least privilege, segregação de contas), proteção em camadas (WAF, ORM, stored procedures) e processos operacionais (testes, monitoramento, playbooks de incidente). Adote prepared statements como regra, valide tudo, minimize privilégios e teste continuamente.
Extras: papel por papel — checklist resumido
Desenvolvedor:
- Usar prepared statements em todas as consultas.
- Validar e higienizar entrada (whitelist).
- Evitar SQL dinâmico.
DBA/Administrador:
- Criar contas com privilégios mínimos.
- Monitorar queries incomuns e logs de auditoria.
Equipe de Segurança:
- Automação de SAST/DAST, pentests periódicos.
- Configurar WAF e integrar alertas.
Materiais semelhantes

Como ver e excluir o histórico do YouTube
Instalar Asterisk: primeiro PBX passo a passo

Corrigir Microsoft Store que não funciona

Varredura e proteção de sites WordPress
