A magia PDO do PHP

Hoje estaremos falando de um problema "GRAVE" que encontramos em muitos websites e sistemas por ai, antigamente era normal contermos falhas de SqlInjection porém hoje em dia isso já não é mais algo aceitavel… Existem inúmeras formas de se proteger contra esse tipo de falha e o mais impressionante é que ainda assim, encontramos vários sistemas com esse problema.
Bom hoje estaremos falando do modulo PDO do PHP e como estar evitando esse tipo de falha. So, Let’s do this.

O que é PDO?

Primeiramente vamos a definição do PDO, PDO é um modulo para conexão com o banco de dados e fazer o gerenciamento de queries. Traduzindo, ele é oque faz a conversa do banco de dados com o PHP. Antigamente era comum usar o modulo mysql https://secure.php.net/manual/pt_BR/function.mysql-connect.php que hoje em dia foi descontinuado pelo PHP por ter muitas falhas de SQLInjection, depois dele veio o mysqli https://secure.php.net/manual/pt_BR/function.mysqli-connect.php que já melhorou bem as coisas e da para evitar muita coisa também. Com o passar do tempo foi lançado o PDO http://php.net/manual/pt_BR/class.pdo.php e atualmente são utilizados tanto o mysqli quanto o PDO. Então porque utilizarmos ele? Simples, porque ele disponibiliza muitas funções de segurança e também é orientado a objetos.

Como funciona o sqlinjection?

A magia PDO do PHP

Essa falha pode ser explorada de inúmeras formas, das mais avançadas as mais iniciantes. Para demostração dela vamos a um pequeno exemplo.
Uma query muito usada em sistemas de login é essa a seguir, porém sem nenhum tipo de validação e nem monitoramento somente executada.

$query = "SELECT * FROM users WHERE user = ‘".$user."’ AND pass = ‘".$pass."’;";

Essa query colocando o usuário fulano e a senha sqlinjection ficaria assim:

SELECT * FROM users WHERE user = ‘fulano’ AND pass = ‘sqlinjection’;

Até ai parece tudo certo não é? somente seria verdade se usuario "e" senha fossem válidos. Reparem no "e" com aspas porque na condição utilizamos o "AND(e)".
Mas e se o usuário malicioso digitasse em um dos campos a seguinte query:
‘or 50=50;# ? Isso na nossa query ficaria da seguinte forma se ele digitasse isso no lugar do user

SELECT * FROM users WHERE user = ” or 50 = 50;# AND pass = ‘sqlinjection’;

Sim isso seria valido e retornaria dados do usuario. Mas porque? Simples a condição AND é valida quando todas as condições são verdadeiras, já a condição OR(ou) é valida se uma delas for verdadeira. Sendo assim user = ” é falsa pois não existiria um usuário vázio porém a outra condição 50 = 50 é verdadeira e sempre será pois 50 é igual a 50 haha… Em seguida ele colocaria um "#" ou as vezes usam "–" que signfica que o resto da linha será ignorado… Acho que deu para entender, bom vamos agora ao PDO.

Se prevenindo com o PDO

O PDO é uma ótima forma de prevenção como já citado, vamos exemplificar a mesma query porém usando o PDO. Só que dessa vez mais detalhado… Primeiro vamos criar uma conexão. Para o exemplo eu criei um banco de dados, com as colunas user e pass e adicionei o usuário fulano e a senha sqlinjection, a senha eu inseri ela em SHA256 salva no banco de dados.
Vamos ao código primeiro vamos criar a conexão, em dbname coloque o nome do seu banco e os outros 2 parametros são login e senha para o banco. Isso dentro da instancia da classe PDO. Estou usando o phpmyadmin.
<?php
function conn(){
try{
$dbh = new PDO('mysql:host=localhost;dbname=pdo','root','Dontgetit');
return $dbh;
}
catch(PDOEception $e){
print "Error!:".$e->getMessage(). "
";
die();
}
}
?>

Bem isso básicamente instancia a classe do PDO e passa os parametros se tudo der certo retorna a conexão. Repare que está dentro de um try/catch pois se algo der errado mostra o erro e fecha a conexão no die();
Vamos verificar agora se o usuário é realmente um usuário cadastrado…
<?php
function isUser($login,$senha){
$pdo = conn();
$sql = 'SELECT * FROM users where user = :login AND pass = :pass';
$pdoexec = $pdo->prepare($sql);
$pdoexec->bindValue(':login',str_replace("'","", $login));
$pdoexec->bindValue(':pass',hash('sha256',$senha));
$run = $pdoexec->execute();
$result = $pdoexec->fetch(PDO::FETCH_ASSOC);
$pdo = null;
if($pdoexec->rowCount() > 0):
return true;
else:
return false;
endif;
}
?>

Explicando: Primeiro na variavel $pdo recebemos a conexão, em seguida inserimos a query na variavel $sql repare que dessa vez temos algo diferente… Adicionamos ":" em palavras, mas calma será explicado, depois no prepare ele checa se é um sql aceito pelo PDO, nas duas linhas abaixo ele faz um bindValue ou seja ele pega a query já validada e substitui aquelas palavras em dois pontos(:login e :pass) pelo usuário e senha digitado, repare que fiz um str_replace não seria bem necessário pois o PDO já verifica isso mas só por mais segurança faço um replace das aspas simples por nada e na senha eu pego oque o usuário digitou e transformo em sha256 para comparar com a do banco. Em seguinda executa a query, encerra a conexão pdo(Mais uma vez não é necessário mas só por garantia, passando a variavel para null) e verifica se retornou algo ou seja se o usuário existe ou se não existe retornando true ou false.

Isso já previne muitooo ataque de SQLInjection e ele tem muito mais funções para proteção se você quiser pode desmembrar o manual do php dele http://php.net/manual/pt_BR/book.pdo.php. Faça bom proveito e não quero ver falha no seu sistema de SQLInjection hein haha.

A magia PDO do PHP

É isso pessoal, vimos que não é tão trivial evitar falhas de SQLInjection e espero que gostem. Enfim, até a próxima.

Source: SQL Injection


Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *