Injeção de SQL é quando o texto que você digita em uma caixa de busca vira "parte de um comando" para o banco de dados. Veja como funciona e como evitá-la de forma confiável (sem passos de ataque).
Por que acontece (o mecanismo)
A causa raiz é montar SQL por concatenação de strings. Misture a entrada direto na instrução e ela pode cruzar a "fronteira de valor" e agir como comando.
✗ Concatenação de strings (perigosa)
Entrada concatenada na instrução → a entrada pode ser lida como parte do comando
✓ Placeholders (segura)
Valores passados para slots ? / $1 como dado → sempre permanecem valores
O dano é "tudo o que aquela conexão de banco pode fazer". Se o banco interno é alcançável, é uma causa clássica de vazamentos em massa, ao lado de RCE e SSRF.
Defesa
Use placeholders / prepared statements (o mais importante)
Não monte SQL por concatenação. Passe os valores via ? / parâmetros nomeados como 'dado'. Só isso quase elimina toda a classe.
Apoie-se no seu ORM / query builder
A maioria dos ORMs usa placeholders por padrão. Quanto menos SQL cru você escrever à mão, mais seguro. Se você precisar escrever SQL cru, sempre parametrize-o.
Usuário de banco com privilégio mínimo
Não conceda ao usuário de banco da aplicação direitos desnecessários (DROP, outras tabelas, operações de admin). Mesmo se comprometido, contenha o dano.
Validação de entrada como complemento
Checagens de tipo/comprimento/formato ajudam, mas não as torne sua defesa principal; elas complementam os placeholders.
A visão deste site: pare de montar SQL cru à mão, para começar
A SQLi é conhecida há muito tempo e ainda acontece, porque é "conveniente" misturar a entrada na instrução. A posição deste site é clara: nunca crie um lugar onde valores sejam concatenados em SQL. Faça dos placeholders ou de um ORM o padrão e essa vulnerabilidade é evitada por design. Não dependa do escape manual.
Atenção: placeholders só carregam valores
Placeholders não cobrem tudo. Eles carregam apenas valores — não a estrutura da consulta, como nomes de tabela, nomes de coluna ou a direção do ORDER BY (asc/desc).
Quando você precisa que isso seja dinâmico (por exemplo, deixar o usuário escolher uma "chave de ordenação" ou "coluna de filtro"), não jogue a entrada no SQL — em vez disso, selecione o nome real de uma allowlist predefinida. "Coluna de ordenação" e "coluna de filtro" são os pontos cegos clássicos onde as pessoas assumem que os placeholders as cobrem.
A entrada não é só campo de formulário
Se você acha que só caixas de busca e formulários de login exigem cuidado, vai deixar casos passar. Valores que podem acabar no SQL chegam por muitos caminhos.
- Headers HTTP (
User-Agent,X-Forwarded-Fore outros) e cookies - Valores em JSON recebidos por uma API, ou lidos de arquivos
- Valores salvos uma vez no banco e depois montados em SQL por outro processo
O último se chama injeção de SQL de segunda ordem. Mesmo que você tenha usado placeholders ao salvar, ela funciona quando outro processo concatena depois o valor armazenado. Não presuma que "veio do meu próprio banco, então é seguro": use placeholders em todo lugar onde SQL é montado.
A explicação deste site sobre falsificação do X-Forwarded-For descreve um caso em que strings de sondagem chegaram num header, mas a injeção de SQL não funcionou porque o valor foi passado com placeholder.
Como difere de termos parecidos
As falhas com "injeção" no nome têm uma coisa em comum: a entrada é lida como comando em outra linguagem. A diferença é onde a entrada vai parar.
| Termo | Onde a entrada vai parar | Dano principal | Correção de raiz |
|---|---|---|---|
| Injeção de SQL | Comandos para o banco de dados (SQL) | Ler, alterar ou apagar dados | Placeholders |
| XSS | HTML ou JavaScript executado no navegador do usuário | Abuso da sessão do usuário, conteúdo falso na página | Escape na saída e CSP |
| Injeção de comandos do SO | Comandos executados pelo shell do servidor | Executar qualquer comando no servidor (RCE) | Use APIs que não passam pelo shell e enviam os argumentos separadamente |
Injeção de SQL e XSS costumam ser citados juntos, mas o dano cai em lugares diferentes: a injeção de SQL atinge o banco de dados no servidor; o XSS atinge o navegador do usuário.
Como os placeholders se chamam nas principais linguagens
Toda linguagem importante oferece uma forma de passar os valores separadamente. Use isto como guia de qual recurso usar na sua stack.
| Linguagem / biblioteca | Recurso a usar |
|---|---|
| Java (JDBC) | PreparedStatement com setters de valor como setString |
| PHP (PDO) | Prepare a instrução com prepare e passe os valores para execute |
| Python (DB-API) | Passe os valores como segundo argumento de execute (não os embuta na string SQL) |
| Node.js (pg e outros) | Símbolos numerados como $1, com os valores passados num array separado |
| C# (.NET) | Adicione os valores aos Parameters do comando |
Em qualquer linguagem, no momento em que você embute valores no SQL com template strings ou +, essa proteção deixa de funcionar.
Casos reais: grandes vazamentos que começaram com injeção de SQL em um produto
A injeção de SQL é conhecida há muito tempo, mas ainda causa grandes vazamentos. Os casos recentes muitas vezes começaram não em código escrito pela própria equipe, mas em um produto que ela usava.
| Caso | O que aconteceu |
|---|---|
| MOVEit Transfer (2023) | Uma injeção de SQL em um produto de transferência de arquivos (CVE-2023-34362) foi explorada antes de existir correção, e dados de mais de 2.700 organizações foram levados, muitos deles por meio de fornecedores (→ o vazamento em massa do MOVEit) |
| Metabase (2026) | Uma injeção de SQL sem autenticação em uma ferramenta de análise (CVE-2026-72898) foi explorada antes da correção, e várias empresas divulgaram vazamentos de dados de clientes (→ exploração e vazamentos do Metabase, em inglês) |
| Núcleo do WordPress (2026) | Combinada com outra falha, uma injeção de SQL sem autenticação podia levar a RCE (→ o CVE-2026-63030 explicado, em inglês) |
Depois do MOVEit, as agências americanas CISA e FBI publicaram em março de 2024 um alerta pedindo que os fabricantes de software eliminem a injeção de SQL, apontando as consultas parametrizadas (placeholders) como a correção. No "CWE Top 25" da MITRE, publicado em dezembro de 2025, a injeção de SQL (CWE-89) está em segundo lugar.
O que fazer depende do seu papel
| Seu papel | Primeira coisa a fazer |
|---|---|
| Você escreve SQL (desenvolvedor) | Pare de concatenar strings; use placeholders ou um ORM. Revise como as funções de SQL cru são usadas |
| Você opera produtos ou software de código aberto (operador) | Verifique os CVEs e o status no KEV dos produtos que você roda e atualize para versões corrigidas. Reduza as telas de administração acessíveis pela internet |
| Ambos | Dê ao usuário de banco do app privilégio mínimo, limitado às tabelas e colunas de que ele precisa |
Como verificar o seu próprio ambiente
Você não precisa digitar strings de ataque para testar isso. O código e as configurações dizem o que você precisa saber.
Encontre SQL montado a partir de strings
Procure no seu código linhas em que palavras-chave de SQL (SELECT, WHERE etc.) aparecem junto com concatenação de strings ou template strings. Verifique também se nenhuma entrada é concatenada em funções de SQL cru ($queryRawUnsafe, whereRaw, DB::raw, raw() e semelhantes).
Anote o que o usuário do banco pode fazer
Verifique quais tabelas o usuário de banco do app pode acessar e o que ele pode fazer nelas (SHOW GRANTS no MySQL, information_schema.role_table_grants no PostgreSQL). Remova direitos de exclusão desnecessários e qualquer acesso a tabelas de outros apps.
Compare os produtos que você usa com dados de vulnerabilidades
Use a Consulta de CVE / KEV para ver as vulnerabilidades conhecidas dos produtos que você roda e se estão sendo exploradas. Para dependências, o osv-scanner verifica todas de uma vez.
Garanta que erros de SQL não apareçam na tela
Em produção, confirme que as mensagens de erro do banco não são mostradas aos usuários como estão. Mantenha os erros detalhados apenas nos logs.
Procure sinais nos seus logs
Verifique se os erros de sintaxe do banco aumentaram de repente e se o seu WAF ou os logs de acesso mostram uma sequência de requisições da mesma origem contendo strings parecidas com SQL. Se sim, revise primeiro o código por trás dessa rota.
Fontes (primárias)
- OWASP, "SQL Injection Prevention Cheat Sheet" (em inglês) — cheatsheetseries.owasp.org (placeholders, cuidados com stored procedures, validação de entrada por allowlist, privilégio mínimo, não depender de escape)
- CISA e FBI, "Secure by Design Alert: Eliminating SQL Injection Vulnerabilities in Software" (25 de março de 2024, em inglês) — cisa.gov
- MITRE, "2025 CWE Top 25 Most Dangerous Software Weaknesses" (dezembro de 2025, em inglês) — cwe.mitre.org (CWE-89 em segundo lugar)
- IPA, "How to Secure Your Web Site" — ipa.go.jp (em japonês; soluções fundamentais vs mitigações)
Leia a seguir
- Glossário: O que é RCE · O que é XSS · O que é o OWASP Top 10
- Explicação: falsificação do X-Forwarded-For e configuração de proxy confiável
- Fundamentos: Fundamentos de segurança