Injection de comandos em bancos de dados continua entre as falhas mais perigosas de aplicacoes web. Na taxonomia OWASP Top 10, a categoria A03:2021 - Injection abarca SQL Injection (SQLi) e NoSQL Injection (NoSQLi), classes de vulnerabilidade que permitem a um atacante subverter consultas e ler, alterar ou destruir dados que jamais deveria tocar. Este guia tecnico mostra como elas funcionam e, sobretudo, como elimina-las de forma definitiva.

O que e injection e por que A03:2021 importa

Uma vulnerabilidade de injection surge quando dados controlados pelo usuario sao interpretados como codigo pelo backend. No caso de bancos de dados, a aplicacao monta uma consulta concatenando texto cru vindo do cliente. Como o interpretador do banco nao distingue a intencao do desenvolvedor da intencao do atacante, qualquer caractere de controle (aspas, operadores, ponto e virgula) muda a estrutura da consulta.

O OWASP consolidou essas falhas em A03:2021 - Injection, que reune SQLi, NoSQLi, injecao de comando de SO, LDAP e ORM injection. O catalogo MITRE/CWE referencia CWE-89 (SQL Injection) e CWE-943 (Improper Neutralization of Special Elements in Data Query Logic) para NoSQL e outras linguagens de consulta. A raiz e sempre a mesma: falta de separacao entre codigo e dados.

O impacto vai muito alem do roubo de credenciais. Uma unica injecao bem-sucedida pode resultar em vazamento integral de base de clientes, alteracao silenciosa de registros financeiros, escalonamento para o sistema operacional do servidor de banco e, em cenarios encadeados, comprometimento total da infraestrutura. Por ser uma falha de logica de construcao da consulta, ela costuma atravessar firewalls de rede e autenticacao: o trafego chega legitimo na porta da aplicacao e so se revela malicioso quando o banco interpreta a carga. Por isso a correcao tem de acontecer no codigo, nao apenas no perimetro.

Anatomia de um SQL Injection

Considere um login que monta a consulta por concatenacao. O exemplo abaixo e classicamente vulneravel:

-- VULNERAVEL (concatenacao de string)
query = "SELECT * FROM users WHERE email = '" + email + "' AND senha = '" + senha + "'"

Se o atacante enviar como e-mail o valor ' OR '1'='1, a consulta resultante torna-se ... WHERE email = '' OR '1'='1' AND senha = '', cuja clausula sempre verdadeira retorna o primeiro usuario da tabela e autentica sem credencial valida. Comentando o resto da consulta com -- ou #, o invasor descarta a verificacao de senha por completo. A partir desse vetor abrem-se diversas tecnicas, agrupadas pela forma como os dados retornam ao atacante.

SQLi in-band

O atacante usa o mesmo canal para injetar e receber os dados. Inclui o UNION-based, em que se anexa UNION SELECT para exfiltrar colunas de outras tabelas, e o error-based, que provoca mensagens de erro do SGBD que vazam estrutura ou conteudo (por exemplo via extractvalue() no MySQL).

SQLi blind (cego)

Quando a aplicacao nao retorna dados nem erros, o atacante infere informacao bit a bit. No boolean-based observa-se a mudanca de comportamento entre AND 1=1 e AND 1=2. No time-based injeta-se um atraso condicional, como SLEEP(5) no MySQL ou pg_sleep(5) no PostgreSQL, e mede-se o tempo de resposta para deduzir verdadeiro/falso.

SQLi out-of-band (OOB)

Quando nem o tempo e confiavel, forca-se o banco a iniciar uma conexao externa (DNS ou HTTP) carregando os dados exfiltrados no proprio nome de dominio. Tecnicas como UTL_HTTP/DBMS_LDAP no Oracle ou xp_dirtree no SQL Server caem nessa familia.

Tipo de SQLiTecnica representativaComo detectar
In-band / UNIONUNION SELECT para anexar resultadosDados extras na resposta; numero de colunas
In-band / Error-basedextractvalue(), conversoes invalidasMensagens de erro do SGBD vazando conteudo
Blind / BooleanAND 1=1 vs AND 1=2Diferenca de pagina entre condicao V/F
Blind / Time-basedSLEEP(5), pg_sleep(5)Latencia condicional na resposta
Out-of-bandDNS/HTTP exfil (UTL_HTTP)Requisicoes de rede saindo do banco

NoSQL Injection: o problema nao desaparece

Bancos NoSQL (MongoDB, CouchDB, Redis) tambem sao injetaveis, mas o vetor muda de sintaxe SQL para a manipulacao de operadores e estrutura de documentos. O CWE-943 cobre exatamente esse cenario.

Injecao de operadores em JSON

Em APIs que recebem JSON e repassam direto ao driver do MongoDB, o atacante substitui um valor escalar por um objeto com operadores. Um login que espera {"user":"ana","pass":"x"} pode ser burlado com:

{ "user": "admin", "pass": { "$ne": null } }

O operador $ne (not equal) faz a condicao de senha casar com qualquer valor diferente de nulo, autenticando sem conhecer a senha. Variacoes usam $gt, $regex ou $where para extrair dados ou montar oraculos cegos analogos ao SQLi boolean/time-based.

Injecao em strings de query e em $where

Frameworks que aceitam parametros de URL aninhados (por exemplo user[$ne]=null via querystring) traduzem automaticamente esses pares em objetos com operadores, reproduzindo o ataque acima sem que o atacante precise enviar JSON. Esse e um vetor comum em APIs Express com qs e bodies urlencoded.

Server-side JavaScript

Recursos como $where e mapReduce avaliam JavaScript no servidor. Se a expressao for montada com entrada do usuario, abre-se execucao de codigo arbitrario dentro do contexto do banco, com payloads do tipo '; return true; var x=' capazes de transformar uma condicao de filtro em um bypass total ou em um oraculo cego. A recomendacao do MongoDB e desabilitar javascriptEnabled e evitar $where sempre que possivel, alem de nunca montar essas expressoes com concatenacao de entrada.

Prevencao definitiva

A boa noticia: injection e uma das classes mais elimimaveis de toda a seguranca de aplicacoes. As defesas abaixo seguem o OWASP SQL Injection Prevention Cheat Sheet, em ordem de prioridade.

1. Prepared statements / parameterized queries (defesa numero 1)

A unica defesa que elimina a falha pela raiz e separar codigo de dados usando consultas parametrizadas. O texto da consulta vai pre-compilado; os valores trafegam por parametros que jamais sao interpretados como sintaxe.

// SEGURO (Java / JDBC)
PreparedStatement ps = conn.prepareStatement(
    "SELECT * FROM users WHERE email = ? AND senha = ?");
ps.setString(1, email);
ps.setString(2, senha);
# SEGURO (Python / psycopg2)
cur.execute(
    "SELECT * FROM users WHERE email = %s AND senha = %s",
    (email, senha))

Em NoSQL, o equivalente e usar os metodos do driver com tipos rigorosos em vez de repassar objetos crus do cliente, e validar que campos de comparacao sejam escalares. Note que a defesa nao e escapar aspas, e sim nunca permitir que a entrada participe da gramatica da consulta. Por isso esta tecnica e considerada a unica que elimina a classe inteira, e nao apenas mitiga payloads conhecidos.

Um detalhe importante: parametros so cobrem valores. Nomes de tabela, nomes de coluna e direcao de ordenacao (ASC/DESC) nao podem ser parametrizados na maioria dos drivers. Quando esses elementos forem dinamicos, eles devem ser resolvidos por uma allowlist explicita no codigo (um mapa de valores permitidos), nunca interpolados diretamente.

2. Stored procedures

Procedures parametrizadas oferecem protecao equivalente desde que nao montem SQL dinamico internamente via concatenacao. Uma procedure que faz EXEC('SELECT ... ' + @param) reintroduz a vulnerabilidade.

3. ORMs com cuidado

ORMs (Hibernate, Sequelize, Django ORM, Prisma) usam parametrizacao por baixo dos panos e sao seguros no caminho feliz. O risco mora nas brechas: queries raw (session.createNativeQuery, .raw(), $queryRawUnsafe) e nomes de coluna/ordenacao dinamicos. Tudo que for raw exige a mesma disciplina de parametros.

4. Validacao de entrada por allowlist

Valide formato, tipo e dominio de cada campo contra uma lista de permitidos (allowlist), nunca de proibidos. Para NoSQL, isso significa rejeitar payloads cujo valor esperado escalar venha como objeto ou contenha chaves iniciadas por $. Faca casting explicito de tipos (string para string, numero para numero) antes de passar ao driver.

5. Menor privilegio no banco

A conta usada pela aplicacao deve ter apenas os privilegios necessarios. Sem DROP, sem FILE, sem acesso a tabelas de sistema. Assim, mesmo que uma injecao escape, o raio de impacto fica contido. Separe contas de leitura e escrita por contexto.

6. Escaping como ultimo recurso

Escapar caracteres especiais e fragil, dependente do SGBD e do charset, e so deve ser usado quando parametrizacao for genuinamente impossivel (por exemplo, identificadores dinamicos validados antes contra allowlist). Nunca trate escaping como defesa primaria.

Defesa em profundidade

Codigo seguro e o nucleo, mas camadas adicionais reduzem risco residual e dao deteccao:

  • WAF: regras (como o OWASP CRS no ModSecurity) bloqueiam payloads conhecidos na borda. Util contra ataques automatizados, mas nao substitui a correcao do codigo.
  • RASP: instrumentacao em runtime que observa a consulta efetivamente enviada ao banco e bloqueia desvios de estrutura.
  • Monitoramento: alertar sobre erros de SQL em rajada, picos de latencia (time-based) e conexoes de saida inesperadas do banco (out-of-band).

Testes: encontrar antes do atacante

Tratamento de injection precisa ser verificavel:

  • SAST: analise estatica do codigo-fonte identifica concatenacao em queries e fluxos de dados nao sanitizados (taint analysis).
  • DAST: testes dinamicos contra a aplicacao rodando, com payloads boolean/time-based automatizados.
  • sqlmap: ferramenta de referencia para explorar e confirmar SQLi em pentest autorizado. Use somente com escopo e autorizacao por escrito; uso sem autorizacao e crime.

Por que confiar em uma so camada e perigoso

Equipes maduras combinam todas as defesas porque cada uma falha de um jeito diferente. Um WAF e contornavel por encoding criativo e novas variantes de payload; uma allowlist mal mantida acumula excecoes; o menor privilegio nao impede a leitura dos dados que a propria aplicacao precisa acessar. So a parametrizacao no codigo fecha a porta de entrada, mas as camadas externas compram tempo de deteccao e reduzem o impacto quando algo escapa. Essa e a essencia da defesa em profundidade aplicada a A03:2021.

Vale tambem instituir um padrao de revisao: nenhuma query construida por concatenacao deve passar no code review, e toda chamada raw de ORM precisa de justificativa e revisao explicita. Em projetos grandes, regras de lint e gates de SAST no pipeline tornam essa politica automatica, evitando que a falha reapareca a cada nova feature.

Como a Decripte ajuda

A Decripte e uma empresa B2B de ciberseguranca que atende organizacoes de 1 a mais de 100.000 colaboradores. Nossas frentes de Application Security e pentest identificam SQLi e NoSQLi no codigo e em runtime, priorizam por risco real de negocio e acompanham a correcao ate a parametrizacao definitiva, com retestes e integracao ao seu ciclo de desenvolvimento.

Quer comecar a mapear sua exposicao sem custo? Comece gratis pelo nosso Intelligence Center, ou conheca os planos de AppSec e pentest dimensionados para o porte da sua operacao.

Referencias

  • OWASP Top 10 - A03:2021 Injection
  • OWASP SQL Injection Prevention Cheat Sheet
  • OWASP Testing Guide - Testing for SQL e NoSQL Injection
  • MITRE CWE-89 - Improper Neutralization of Special Elements used in an SQL Command
  • MITRE CWE-943 - Improper Neutralization of Special Elements in Data Query Logic