Camadas de abstração de banco de dados como Portable Data Objects (PDO) do PHP não são um conceito novo, mas muitos desenvolvedores não parecem perceber o benefício de segurança que estão obtendo gratuitamente ao usá-las – proteção inerente contra injeção de SQL.
A injeção de SQL é o estouro de buffer do mundo dos aplicativos da web – existe desde sempre, e todo desenvolvedor de aplicativos da web deve saber como escrever um código seguro que não seja vulnerável a ele. Para quem não sabe, injeção de SQL é uma técnica por meio da qual um invasor malicioso pode explorar a validação de dados inadequada para injetar código SQL arbitrário nas consultas do seu aplicativo e executá-lo como se fosse uma consulta legítima. Não vou aprofundar muito na injeção de SQL neste artigo, mas aqui está um exemplo simples:
A página inicial de seu aplicativo possui um formulário de login, que é submetido a um script PHP para validar as credenciais do usuário e permitir ou negar acesso ao aplicativo. O formulário de login envia duas variáveis por POST da seguinte maneira:
username = fred & password = Fr3dRul3z
Os dados POSTados são então usados para construir uma consulta SQL para validar as credenciais, como esta:
$ sql = “SELECT * FROM usuários WHERE username = ‘”. $ _ REQUEST[‘username’]. “‘AND senha ='”. $ _ REQUEST[‘password’]. “‘”;
Isso resultaria na consulta SQL:
SELECT * FROM users WHERE username = ‘fred’ AND password = ‘Fr3dRul3z’
Supondo que exista uma linha no banco de dados com essas credenciais, o usuário teria permissão para fazer login. Um invasor poderia facilmente contornar esse esquema de autenticação escapando do campo de nome de usuário para a consulta SQL, não inserindo nada no campo de senha e isso no campo de nome de usuário:
‘OU 1 == 1 –
A string de consulta SQL resultante seria assim:
SELECT * FROM users WHERE username = ‘fred’ OR 1 == 1 – ‘AND password =’ ’
O que, como tenho certeza que você pode ver, selecionaria todos os usuários do banco de dados, pois a condição 1 == 1 sempre será verdadeira. O resto da consulta é descartado com o operador de comentário ‘-‘. A maneira de evitar esse tipo de ataque é higienizar os dados enviados ao formulário, escapando de tudo o que poderia ser usado para escapar dos limites das aspas em torno dos campos (por exemplo, mysql_real_escape_string () se você estiver usando MySQL). No entanto, em uma terra distante, alguém estava inventando camadas de abstração de banco de dados …
O objetivo principal das camadas de abstração de banco de dados como PDO é a abstração limpa em seu código, longe da plataforma de banco de dados – então, teoricamente, você poderia alternar as plataformas de banco de dados de, digamos, MySQL para PostgreSQL ou Oracle com mudanças mínimas no código. Na prática, isso depende muito de quanto seu código depende de recursos específicos da plataforma, como gatilhos e procedimentos armazenados, mas se você não está contando com eles e está apenas fazendo operações simples de INSERT / UPDATE / DELETE, é um passeio grátis . Parece moderadamente útil, mas nada excitante, certo? Certo. Outro recurso interessante inventado há muito tempo são as instruções preparadas, e a maioria das camadas de abstração do banco de dados (incluindo PDO) implementam isso como uma forma de realizar a mesma consulta várias vezes com conjuntos de dados diferentes (por exemplo, inserir um monte de novas linhas). Agora, ao construir instruções com PDO, em vez de construir a string SQL manualmente conforme demonstrado anteriormente, construímos a instrução com marcadores como este:
$ sql = “INSERT INTO frutas (nome, preço) VALORES (?,?)”;
e, em seguida, execute a consulta com um conjunto de dados passado para a camada de abstração da seguinte maneira:
$ sth = $ dbh-> preparar ($ sql);
$ sth-> execute (array ($ fruta, $ preço));
Quando os dados são entregues ao PDO dessa forma, ele passa os dados diretamente para o driver do banco de dados ou cria a consulta internamente de maneira segura com quaisquer dados potencialmente maliciosos codificados ou com escape. Como você pode ver, essa é uma maneira fácil de contornar o problema da injeção de SQL.
No entanto, as declarações preparadas com DOP não são todas filhotes e arco-íris. O uso de instruções preparadas pode apresentar uma série de advertências interessantes das quais os desenvolvedores devem estar cientes. Por exemplo, nas declarações preparadas da API do cliente MySQL não podem executar certos tipos de consultas[1] e eles não usam o cache de consulta[1][2] o que pode ter um impacto no desempenho do seu aplicativo.
A segurança inerente ao uso de declarações preparadas parece ótimo, mas os desenvolvedores não devem permitir que o PDO e outras camadas de abstração / implementações de declarações preparadas os embalem em uma falsa sensação de segurança. Dados não confiáveis sempre devem ser validados e higienizados, o PDO é apenas outra linha de defesa. Ele não cobre o território de uma infinidade de outras vulnerabilidades de validação de entrada, como script entre sites, mas faz um bom trabalho de proteção de aplicativos contra injeção de SQL. A melhor estratégia é apenas permitir dados bons conhecidos colocando caracteres na lista de permissões e combinando dados de entrada com padrões de expressão regular, então usando instruções preparadas para capturar qualquer injeção SQL que a validação de entrada perca, tudo em conjunto com um firewall de aplicativo da web como ModSecurity.
PDO foi integrado ao PHP desde a versão 5.1.0, que foi lançada em novembro de 2005. A menos que você tenha um bom motivo para não usá-lo em seus aplicativos PHP, você deveria estar – é um substituto portátil para o antigo mysql_ * funções e outras funções específicas da plataforma com o benefício adicional de proteção contra injeção de SQL.