Como Reconhecer e Prevenir a Injeção de SQL

O que é a injeção de SQL
A injeção de SQL (SQLi) é um dos tipos de ataque mais antigos e perigosos contra aplicações web. O ataque funciona através da injeção, por parte de um atacante, de código SQL malicioso em campos de entrada (formulários, parâmetros de URL, cookies) que a aplicação utiliza para construir consultas SQL à base de dados. Se a aplicação não validar e sanitizar a entrada do utilizador antes de a incorporar numa consulta SQL, o atacante pode manipular a consulta para ler, modificar ou eliminar dados da base de dados.
Segundo a lista OWASP Top 10, os ataques de injeção estão há anos entre as três vulnerabilidades web mais críticas. Um ataque de injeção de SQL bem-sucedido pode resultar no roubo de toda a base de dados (contas de utilizador, palavras-passe, dados pessoais), na modificação ou eliminação de dados, na evasão da autenticação (login sem palavra-passe), na execução de comandos no sistema operativo do servidor e no comprometimento total do servidor.
Como funciona a injeção de SQL
Princípio básico
Imagine um formulário de login que verifica um nome de utilizador e uma palavra-passe. A aplicação constrói uma consulta SQL que tem mais ou menos este aspeto: SELECT * FROM users WHERE username = 'nome_introduzido' AND password = 'palavra_passe_introduzida'. Se a aplicação se limitar a inserir a entrada do utilizador na consulta sem qualquer verificação, o atacante pode introduzir um valor especial no campo do nome de utilizador que altera a lógica da consulta. Por exemplo, uma entrada que contenha um apóstrofo seguido de código SQL pode fechar o literal de string e adicionar uma condição que é sempre verdadeira, contornando a verificação da palavra-passe.
Tipos de ataques de injeção de SQL
Existem vários tipos de ataques de injeção de SQL. O In-band SQLi é o mais comum, em que o atacante utiliza o mesmo canal de comunicação para enviar o ataque e receber os resultados. Divide-se em Error-based SQLi (utiliza mensagens de erro da base de dados para extrair informação) e Union-based SQLi (utiliza o operador UNION para combinar os resultados de uma consulta maliciosa com uma legítima). O Blind SQLi é um tipo em que o atacante não vê resultados diretos, mas pode inferir informação com base no comportamento da aplicação. O Boolean-based blind SQLi envia consultas que devolvem verdadeiro ou falso e infere os dados caráter a caráter com base nas diferenças de resposta. O Time-based blind SQLi utiliza funções de pausa do SQL (SLEEP, WAITFOR DELAY) para determinar se uma condição é verdadeira com base no tempo de resposta. O Out-of-band SQLi utiliza um canal diferente para a exfiltração de dados, como pedidos DNS ou HTTP que a base de dados envia para o servidor do atacante.
Detetar vulnerabilidades de injeção de SQL
Testes manuais
A forma mais simples de testar vulnerabilidades de injeção de SQL é injetar carateres especiais nos campos de entrada. Um apóstrofo (') é o primeiro teste — se a aplicação devolver um erro da base de dados, existe uma potencial vulnerabilidade. Um duplo apóstrofo ('') não deve provocar um erro se um único o provocou. Os comentários SQL (-- ou #) podem ser usados para comentar o resto da consulta. Os operadores lógicos (OR 1=1, AND 1=2) podem revelar vulnerabilidades baseadas em booleanos. O comando SLEEP ('; WAITFOR DELAY '0:0:5'--) revela vulnerabilidades baseadas em tempo se a página atrasar a sua resposta.
Ferramentas automatizadas
Para testes sistemáticos, utilize ferramentas especializadas. O SQLMap é a ferramenta open-source mais conhecida para deteção e exploração automática de vulnerabilidades de injeção de SQL — suporta todos os tipos de SQLi e a maioria das bases de dados. O Burp Suite Professional tem um scanner integrado para injeção de SQL e outras vulnerabilidades web. O OWASP ZAP é uma alternativa gratuita ao Burp Suite com um sólido scanner de SQLi. O Acunetix e o Netsparker são scanners comerciais de vulnerabilidades web com deteção avançada de SQLi.
Sinais de comprometimento
Se suspeitar que o seu site já foi alvo de uma injeção de SQL, verifique o seguinte: entradas invulgares nos registos do servidor web (URLs com palavras-chave SQL), contas de utilizador novas ou modificadas na base de dados (sobretudo contas de administrador), dados modificados sem o seu conhecimento, ficheiros novos no servidor (web shells) e aumento do tráfego para páginas específicas com parâmetros invulgares. Reveja também os ficheiros de registo da base de dados em busca de consultas inesperadas.
Prevenção — Prepared Statements
O que são os prepared statements
Os prepared statements (consultas parametrizadas) são a proteção mais eficaz contra a injeção de SQL. Em vez de inserir a entrada do utilizador diretamente numa consulta SQL como texto, um prepared statement separa a estrutura da consulta dos dados. Primeiro define-se a estrutura da consulta com placeholders para os dados e, em seguida, os dados são enviados separadamente. A base de dados trata os dados apenas como valores, nunca como código SQL, tornando a injeção impossível.
Implementação em diferentes linguagens
O PHP com PDO (PHP Data Objects) utiliza o método prepare() para preparar uma consulta com placeholders (:username, :password) e execute() com um array de valores. A extensão MySQLi suporta prepared statements com placeholders ? e bind_param() para associar valores com tipos de dados. O Python com sqlite3 ou psycopg2 utiliza placeholders ? ou %s. O Java utiliza a classe PreparedStatement com os métodos setString(), setInt(). As bibliotecas de Node.js como mysql2 e pg suportam consultas parametrizadas com placeholders ? ou $1. Independentemente da linguagem de programação, o princípio é o mesmo — nunca concatenar a entrada do utilizador com uma consulta SQL sob a forma de strings.
Métodos de prevenção adicionais
Validação de entrada
Para além dos prepared statements, valide sempre a entrada do utilizador. A validação por lista branca (whitelist) permite apenas valores esperados — se um campo deve conter um número, verifique que é realmente um número antes de o processar. Para campos de texto, restrinja os carateres permitidos, o comprimento da entrada e o formato (regex). Nunca confie apenas na validação do lado do cliente (JavaScript), porque um atacante pode contorná-la — a validação tem de ser implementada no servidor.
Stored Procedures
As stored procedures são código SQL armazenado e executado no servidor de base de dados. Quando corretamente escritas (sem SQL dinâmico dentro do procedimento), proporcionam uma camada adicional de proteção, porque a aplicação invoca o procedimento com parâmetros em vez de enviar consultas SQL em bruto. Contudo, as stored procedures por si só não são uma garantia de segurança — se os procedimentos construírem internamente consultas dinâmicas a partir de parâmetros, a vulnerabilidade continua a existir.
ORM (Object-Relational Mapping)
As bibliotecas ORM como o Eloquent (Laravel), o SQLAlchemy (Python), o Hibernate (Java) e o TypeORM (Node.js) utilizam automaticamente prepared statements em todas as consultas, eliminando a maior parte do risco de injeção de SQL. No entanto, a maioria dos ORM permite consultas SQL em bruto para operações complexas — nesses casos, tem de utilizar manualmente prepared statements. Um ORM não substitui o conhecimento de segurança SQL, mas reduz significativamente a superfície de ataque.
Princípio do menor privilégio
Configure a base de dados de forma a que a aplicação utilize uma conta com os privilégios mínimos necessários. Uma aplicação web normalmente precisa dos privilégios SELECT, INSERT, UPDATE e DELETE em tabelas específicas. Não conceda os privilégios DROP, ALTER, CREATE ou FILE à conta da aplicação. Se um atacante conseguir uma injeção de SQL, os privilégios restritos impedem a eliminação de tabelas, a modificação da estrutura da base de dados e o acesso ao sistema de ficheiros do servidor.
Proteção WAF contra injeção de SQL
Como um WAF deteta SQLi
Um Web Application Firewall (WAF) analisa os pedidos HTTP e bloqueia os que contêm padrões de injeção de SQL. O WAF reconhece palavras-chave SQL em locais inesperados (SELECT, UNION, DROP em parâmetros de URL), carateres especiais usados em ataques SQLi (apóstrofos, comentários, operadores lógicos), payloads SQLi conhecidos de uma base de dados de assinaturas e anomalias na estrutura do pedido que indicam uma tentativa de injeção.
Limitações do WAF
Um WAF não substitui código seguro. Atacantes experientes podem contornar um WAF utilizando técnicas de codificação (URL encoding, Unicode, dupla codificação), comentários e espaços para quebrar assinaturas, sintaxes SQL alternativas que o WAF não reconhece e testes incrementais para determinar que regras o WAF utiliza. O WAF é uma camada de proteção adicional (defense in depth), mas a proteção principal tem de estar no código da aplicação, através de prepared statements e validação de entrada.
Injeção de SQL no WordPress
Mecanismos de proteção do WordPress
O núcleo do WordPress utiliza o método $wpdb->prepare() para todas as consultas à base de dados, que é a implementação de prepared statements do WordPress. Este método utiliza placeholders ao estilo sprintf (%s para strings, %d para inteiros, %f para floats) e faz automaticamente o escaping dos valores. No entanto, as vulnerabilidades surgem mais frequentemente em plugins e temas que não utilizam $wpdb->prepare() ou que constroem consultas concatenando strings manualmente.
Proteger um site WordPress
Para proteger um site WordPress contra a injeção de SQL, atualize regularmente o núcleo do WordPress, os plugins e os temas, porque os patches de segurança corrigem frequentemente vulnerabilidades de SQLi. Utilize apenas plugins e temas de fontes fidedignas (repositório WordPress.org, fornecedores comerciais reconhecidos). Instale um plugin de segurança (Wordfence, Sucuri, iThemes Security) que inclua proteção WAF. Consulte também o nosso guia para proteger um site contra hackers. Remova plugins e temas não utilizados, porque mesmo plugins desativados podem ser explorados. Restrinja o acesso à base de dados — o WordPress precisa apenas de um utilizador com acesso à sua base de dados.
Erros comuns que deixam um site vulnerável
- SQL dinâmico no código: Concatenar a entrada do utilizador com uma consulta SQL sob a forma de string é a principal causa das vulnerabilidades de injeção de SQL. Utilize sempre prepared statements.
- Confiar na validação do lado do cliente: A validação em JavaScript pode ser contornada — toda a validação tem de existir no servidor.
- Mensagens de erro detalhadas: Apresentar erros SQL aos utilizadores revela a estrutura da base de dados e facilita o ataque. Em produção, registe os erros internamente e apresente uma mensagem genérica aos utilizadores.
- Software desatualizado: Versões antigas de CMS, frameworks e bibliotecas têm frequentemente vulnerabilidades SQLi conhecidas com exploits publicamente disponíveis.
- Um único utilizador de base de dados para tudo: Utilizar uma conta root para a aplicação dá ao atacante o controlo total da base de dados em caso de ataque bem-sucedido.
Conclusão
A injeção de SQL é uma ameaça séria que pode comprometer totalmente o seu site e os dados dos utilizadores. A prevenção é relativamente simples — utilize prepared statements em todas as interações com a base de dados, valide a entrada do utilizador no servidor, aplique o princípio do menor privilégio e mantenha o software atualizado. Um WAF proporciona uma camada de proteção adicional, mas não substitui código seguro. Com o alojamento BeoHosting, todos os servidores incluem um WAF ModSecurity configurado que deteta e bloqueia tentativas de injeção de SQL, mas recomendamos que o seu código siga também as melhores práticas de programação segura.
BeoHosting Team
10+ anos de experiência — Especialistas em alojamento web e infraestrutura
- Web Hosting
- WordPress Hosting
- VPS
- Dedicated Serveri
- Domeni
- SSL
- cPanel
- LiteSpeed
- Linux administracija
- DNS
Última atualização: