[PHP] SQL Injection: Cuidado!

Há alguns dias, me deparei com uma falha de segurança em um site que desenvolvi para uma empresa. Na verdade, não houve qualquer tipo de ataque, mas após ter sido submetido a um conjunto de testes, notei que o site estava vulnerável a uma técnica conhecida como SQL Injection, ou Injeção de SQL. Se você é desenvolvedor web e não conhece este termo, confira o artigo!

Introdução

A maioria dos sites normalmente possuem uma tela de login e senha para acessar um conteúdo ou uma área restrita. No meu caso, é um site que proporciona um sistema on-line para emissão de pedidos, utilizado pelos vendedores da empresa. O processo de login é realizado de modo tradicional, validando os dados do usuário em uma consulta SQL da seguinte forma:

O usuário entra com o login e senha em campos do tipo “text” e “password”, respectivamente:

Ao pressionar ENTER ou clicar no botão de login, o site leva os dados digitados para uma página PHP:

Essa página, por sua vez, verifica se o login e senha existem no banco de dados, através de uma SQL:

Se os dados estiverem corretos, a página principal da área restrita é exibida.
No entanto, apesar de funcional, o código acima não está preparado para evitar uma tentativa de SQL Injection!

Definição

O SQL Injection consiste em anexar uma condição SQL dentro do código-fonte. Aqui, poderíamos literalmente utilizar a palavra “injetar”. Por meio dessa técnica, é possível adicionar uma condição OR na instrução SQL para que, mesmo que o usuário e senha estejam inválidos, o Select retorne um resultado verdadeiro. Em outras palavras, é uma forma de alterar a instrução SQL original para burlar a validação de segurança de um site. Este assunto é bastante discutido na comunidade de desenvolvimento web em virtude da sua importância e do risco relacionado à invasão de sites.


Mas o que isso tem a ver com o código PHP?

Eis que chegamos no objetivo do artigo. Na página de login, o que acontece se digitarmos a condição SQL abaixo nos campos de login e senha?

Exato! A instrução Select retornará verdadeiro! Ao invés dos dados de login e senha, haverá uma instrução SQL para “enganar” o banco de dados. Traduzindo em código, observe o resultado da instrução SQL que será executada no código PHP:

Note que há duas condições OR que verificam se 1 é igual a 1.


E qual a finalidade dessa condição?

Simples. Vamos analisar a SQL em partes:

Nessa condição, o Select irá retornar verdadeiro caso o login seja em branco (vazio), ou caso o número 1 seja igual a 1. Porém, como a segunda condição SEMPRE será verdadeira, a primeira condição é invalidada. O mesmo acontece para a senha:

Observe que, mesmo que o login e senha estejam incorretos, as condições OR sempre serão atendidas. Na prática, a instrução SQL se comportará dessa forma:

Logo, ao executar essa SQL, a consulta retornará um estado verdadeiro e o usuário terá acesso à área restrita. Assustador, não?

Solução

Graças aos recursos do PHP, há uma função chamada addslashes que adiciona barras invertidas antes de qualquer caractere de escape, como as aspas simples. Se utilizarmos essa função no nosso código, o SQL Injection perderá o efeito! Portanto, vamos modificar o código que recebe os dados do login e utilizar o addslashes:

Como impacto, a instrução SQL também será afetada e o retorno será falso:

O addslashes é uma das alternativas para impedir o SQL Injection. Além dessa opção, você também pode, por exemplo, substituir as aspas simples por uma string vazia, o que também irá invalidar o SQL Injection. Porém, atente-se que neste caso, os usuários que tiverem aspas simples no login ou na senha terão problemas ao acessar a página. Outra alternativa é tratar essa ameaça no próprio código-fonte, criando uma função que verifique possíveis cláusulas SQL nos dados recebidos.
Independente da solução utilizada, é muito importante realizar vários testes para conferir se a brecha se segurança realmente foi corrigida.

Antes de finalizar, gostaria de fazer um agradecimento especial ao meu irmão, Danilo Celestino, pela orientação nessa questão do SQL Injection e pela ajuda para solucioná-lo, o que me motivou a elaborar este artigo!

 

Agradeço pela visita, leitores! Abraço!


André Celestino