Entre para a LISTA VIP da Black Friday

00

DIAS

00

HORAS

00

MIN

00

SEG

Clique para saber mais

Evitando SQL Injection com PHP

Evitando SQL Injection com PHP

Quando desenvolvemos nossos sistemas, é normal que a gente faça pensando no usuario final. Portanto, ao criar um formulário de login que verifica um email e senha no banco de dados já temos em mente o que precisamos fazer no back-end:

Neste post vamos trabalhar com PDO. Com essa extensão, teríamos algo como:


public function login($email,$senha) {

$query = "SELECT * FROM Usuario WHERE Email = '". $email. "' AND Senha = '". $senha."'";

$result = $this->con->query($query); 
$usuario = $result->fetchObject('Vendor Model Usuario');
return $usuario;
}
Banner da promoção da black friday, com os dizeres: A Black Friday Alura está chegando. Faça parte da Lista VIP, receba o maior desconto do ano em primeira mão e garanta bônus exclusivos. Quero ser VIP

Beleza, assim conseguimos verificar o email e a senha. Para um usuário comum, nosso método funciona perfeitamente!

Mas, um usuário malicioso, com um pouco de conhecimento, pode tentar passar códigos SQL nos inputs do form, como por exemplo:

Nossa query completa ficaria:

SELECT * FROM Usuario Where Email = '[email protected]' AND Senha = '' or id ='1'

Ou seja, estamos selecionando tudo da tabela Usuario onde o email é igual a "[email protected]" e senha é vazia OU o id igual a 1.

A setença OR ID = 1 será verdadeira se houver o registro no banco. Como os valores de id, normalmente, são auto incrementados isso fará com que o usuário malicioso entre no nosso sistema como o usuario de id = 1.

Mudar a query desta forma é o que chamamos de SQL Injection. Existem diversas formas de lidar com isso, a mais comum é usar prepared statement, uma forma de escrever queries passando atributos ao invés de concatenar as variáveis com a string.

Com PDO, nosso prepared statement ficará:


public function login($email,$senha) { 

$query = "SELECT \* FROM Usuario WHERE Email = :email AND Senha = :senha";

$statement = $this->con->prepare($query);
$statement->bindValue(":email",$email); 
$statement->bindValue(":senha",$senha);

$statement->execute(); 
$usuario = $statement ->fetchObject('Vendor Model Usuario'); 
return $usuario; 
}

Ao invés de usar a função query da conexão, podemos usar a função ->prepare() e então passar os valores de Email e Senha pelo método ->bindValue() que realizará uma verificação do conteudo das variáveis $email e $senha evitando os casos mais comuns de SQL Injection.

Somente após, associamos aos atributos :email e :senha da query e, por fim, é executada a query!

Além disso, aumentamos a semantica já que usamos parametros na query ao invés de concatenar os valores das variáveis $email e $senha na string $query.

Nesse momento, nossa query está algo como:

SELECT * FROM Usuario Where Email = '[email protected]' AND Senha = ' or id =1'

Ou seja, estamos procurando na tabela Usuario a instância de email "[email protected]" e senha "or id =1". Logo, a senha não será validada e nosso usuario malicioso não entrará em nosso sistema!

É extremamente importante pensarmos em todos os tipos de usuario quando desenvolvemos nossos sistemas. Por isso, temos que estar sempre atentos ao desenvolver nossas queries e nos proteger contra SQL Injection.

E você, o que achou de SQL Injection? Gostou de prepared statements? Compartilhe sua opinião com a gente!

Quer aprender mais sobre PHP? Conheça a formação desenvolvedor PHP junior aqui da alura! Ou então, que tal ir além e conhecer mais a fundo a extensão PDO, suas vantagens e desvatagens? Faça o curso de PDO com a gente aqui na Alura!

André Chaves
André Chaves

Instrutor na Caelum e líder técnico na Hefesto Software House. No tempo livre, escritor no blog https://medium.com/code-maestro. Twitter @andrechavesg

Veja outros artigos sobre Programação