Blindando Seu Código PHP

Um programador tem que ser desconfiado, sempre esperar o pior, do usuário e principalmente de outros programadores. O mundo dos bits tem suas hienas à espreita para sugar todos os dados do seu website e depois te deixar com uma dor de cabeça das mais violentas.

Nos ataques, conhecidos como injeção de código e sql injection o objetivo é se aproveitar de possíveis brechas de segurança no seu script e inserir instruções que darão acesso ao invasor, a todas as informações do seu banco de dados. E não é porque você não fez um website para uma multinacional ou portal que não precisa se preocupar com ataques. Os scripts de ataque não procuram por tamanho do website, mas por dados.

As duas modalidades mais comuns nas tentativas de injeção de código são através de formulários e urls. Sendo assim você deve se preocupar tanto em validar as informações inseridas pelo usuário, como a estrutura das suas páginas e como os dados são passados entre elas.

O PHP fornece uma ampla gama de funções para validação de dados. Vamos conhecê-las e aprender a tornar nossos scripts verdadeiras fortalezas.

Cofre

Injeção De Código Na URL

A criação de urls amigáveis por si só já ajuda a evitar esse tipo de ataque. Ele altera os valores das variáveis que são passados de uma página para outra.

Um exemplo comum é quando são listados os produtos à venda no website. Em uma página são mostradas somente a foto e o preço, ao clicar sobre eles é passada a “id” correspondente para outra página que mostra os detalhes. A url no caso fica assim:

http://www.site.com/descricao.php?id=10

A consulta é essa:


<?php

$id = $_GET[‘id’] //10
$busca = mysql_query(“SELECT * FROM produtos WHERE id=’$id’”);
// $busca = mysql_query(“SELECT * FROM produtos WHERE id=10”);

?>

Mas o invasor deseja ver mais que apenas os detalhes do produto. Então ele se utiliza de uma SQL-Injection clássica, e altera o endereço para pesquisa:

http://www.site.com/descricao.php?id=’ OR 1=1

Veja o que ocorre devido à falta de validação:


<?php
$id = $_GET[‘id’] //’ OR 1=1
$busca = mysql_query(“SELECT * FROM produtos WHERE id=’$id’”);
// $busca = mysql_query(“SELECT * FROM produtos WHERE id=’’ OR 1=1”);
?>

A consulta não vai encontrar o “id” vazio, mas considera que 1 é igual a 1. E como estamos falando de lógica, ela vai ser considerada verdadeira e vai retornar todos os registros da tabela! E se ao invés da tabela produtos fosse a tabela usuários? Imaginou o tamanho do problema?

Se Protegendo Com O filter_var

É muito simples se proteger contra esse ataque. Como os valores das ids são números, é só garantir que o valor passado seja numérico, pois as tentativas de SQL-Injection sempre utilizam strings.


<?php

$id = $_GET[‘id’] ;//  ‘ OR 1=1
$id = filter_var($id, FILTER_SANITIZE_NUMBER_INT); //resulta em 11

?>

Simples, não? A função só deixou número e nossa consulta vai ocorrer como o esperado.

A função filter_var é uma grande facilitadora nas validações. Ela só precisa que você informe qual variável será analisada, o que você quer checar e se existe alguma ressalva.
A sintaxe simplificada da função é esta:

filter_var ($variable, $filter, $options)

Com ela você pode validar também endereços de e-mail, ips, floats, urls, caracteres especiais. Uma função bastante versátil. Veja mais sobre ela na documentação do PHP (http://docs.php.net/manual/pt_BR/function.filter-var.php)

int()

Mas se você quer permitir somente números como valor da variável, o código fica desta maneira:


<?php

$id = (int)$_GET[‘id’] ;//  ‘ OR 1=1
echo $id // 0

?>

Como o valor passado é uma string, na tentativa de conversão o resultado será nulo, ou numericamente 0. E problema resolvido!

Para tornar o prejuízo menor, você também pode limitar o retorno das consultas com o LIMIT.

Acima trabalhamos apenas em garantir que estamos recebendo um número. E é consideravelmente mais fácil do que garantir que a string que nós esperamos é a que esta sendo passada. Vamos ao trabalho.

Validando Strings

Você possui um blog onde posta suas idéias e repassa conhecimento. Tem espaço para comentários. Tudo muito democrático. Você acredita na boa intenção das pessoas e não se preocupa em validar os dados (ou seria preguiça?). Então vem um desocupado e resolve comentar nos seus artigos inserindo um link para a página dele esperando melhorar de posição nas pesquisas do Google. E depois desse vem outro e mais outro. Fazem uma festa nos comentários.

htmlspecialchars() e htmlentities()

Para dar um jeito nestes fanfarrões você pode bloquear os caracteres HTML que são inseridos nos comentários. Para isso existe a função htmlspecialchars().Ela converte caracteres que possuem significado para o HTML (&, “, ‘,). Ele transforma, por exemplo, aspas duplas em " . A sintaxe é

htmlspecialchars($string, $quote_style, $charset, $double_encode)

O primeiro parâmetro é a variável a ser analisada, no seguinte você informa o que será feito com aspas duplas e simples. Por padrão ele converte somente aspas duplas. No terceiro argumento você informa a codificação dos caracteres e no último você informa se deseja não converter aspas duplas.


<?php

$variavel = htmlspecialchars(“<a href=’http://www.site.com’>Link</a>”);
echo $variavel // &lt; a href=&#039; http://www.site.com &#039;>Link</a>&lt;

?>

Um parente do htmlspecialchars() é o htmlentities() que abrange mais alguns caracteres, mas trabalha com a mesma essência. Para reverter a codificação utilize html_entity_decode().

strip_tags()

Uma terceira maneira de lidar com tags HTML e também PHP é utilizando a strip_tags(), que retira as tags da string. Primeiro a sintaxe:

strip_tags($string, $allowable_tags)

Você fornece a string a ser tratada e resolver permitir a tag

, então preenche o segundo parâmetro.


<?php

$texto = '<p>Texto.</p><!-- Comment --> <a href="#ancora">Link</a>';
echo strip_tags($texto); // Texto. Link

?>

Com apenas uma função você se livra das tags indesejadas! Bem… Tem alguns problemas. Se a tag estiver pela metade ou incompleta, pode ocorrer de ser retirado mais caracteres que o necessário. Se você permitir uma tag, os atributos inseridos nela não serão validados e isso abre uma brecha para manipular o código.

addslashes()

Esta função adiciona uma barra invertida antes da aspas simples, duplas, barra invertida e valores nulos. Você só precisa passar a string a ser alterada.

Mas antes de utilizar o addslashes() veja se a diretiva magic_quotes_gpc do PHP esta setada. Pois ela faz o mesmo trabalho automaticamente. Para descobrir se ela esta setada execute:

Magic Quotes

Se ela estiver on não utilize o addslashes() caso contrário serão aplicadas duas barras invertidas.

mysql_real_escape_string()

Você pode dizer que existe uma grande variedade de funções para tratar aspas e se estiver se perguntando qual a finalidade, volte um pouco no início do tutorial. Veja como uma SQL-Injection utiliza aspas. Isso porque nas consultas mysql, os termos precisam estar entre aspas. Para lidar em última instância com elas existe também o mysql_real_escape_string(). Com a seguinte sintaxe:

mysql_real_escape_string($string, $link_identifier)


<?php

$valida = mysql_real_escape_string($_POST[‘variavel’]);

?>

Se você tiver utilizado o addslashes(), não utilize o mysql_real_escape_string() senão serão aplicadas duas barras invertidas ao invés de somente uma.

preg_replace()

Esta não é uma função para validação, mas funciona muito bem como mais uma ferramenta de proteção.

preg_replace($pattern, $replacement, $subject)

Ela procura os termos listados no primeiro parâmetro e substitui estes, pelos caracteres do parâmetro seguinte, analisando a string apontada no ultimo parâmetro.


<?php

$recebe = preg_replace(sql_regcase("/(from|select|insert|delete|where|drop table|show tables)/"),'', $string);  

?>

No código acima a função procura pelas palavras reservadas do mysql que possam existir na variável “$string” e as substitui por nada. O sql_regcase no meio é para que a busca seja case insensitive.

Juntando As Partes

Sem dúvida funções que nos ajudam a validar e tratar os dados vindos do usuário não faltam. Claro que não podemos esperar que utilizando apenas uma delas nosso trabalho esteja feito. Por isso é importante saber o que cada uma faz para que possamos utilizá-las em conjunto e dificultar a ação dos invasores.

Vamos criar uma pequena função para validar strings.


<?php

   function AntiSqlInjection($recebe)
   {
       // Verifica a configuração se "magic_quotes_gpc" esta setado, caso não esteja aplicamos o addslashes
     if (!get_magic_quotes_gpc)
     {
       addslashes($recebe);
     }
       // Limpamos as tags HTML
       $recebe = strip_tags($recebe);
    
       // Procuramos as palavras reservadas sql e deletamos
       $recebe = preg_replace(sql_regcase("/(from|select|insert|delete|where|drop table|show tables)/"),'', $recebe);  
       return $recebe;
   }

$string = "select alguma coisa e delete";

$texto = AntiSqlInjection($string);
echo $texto; // alguma coisa e

?>

Este script pode ser melhorado e se tornar ainda mais útil, mas ajuda a entender como juntar as partes.

Procurar formas de manter seus códigos e aplicações seguras deve ser uma constante para você como programador. Não se contente apenas em utilizar as funções mostradas aqui, pois as tentativas de invasão tomam as mais diversas formas, como submissões consecutivas, upload de arquivos maliciosos e outras que se fossem analisadas aqui tornariam o tutorial gigantesco.

Aprofunde seu conhecimento sobre as funções acima e outras acessando a documentação do PHP online.

Be Sociable, Share!

11 Comentários

  1. flavio

    Cara, muito bom sua dica.
    deixo aqui meu agradecimento

  2. arthur

    Muito bom msm…

    obrigado pela dica

  3. Constantine

    Cara, excelente!!!!

    Vim procurando por uma dica e achei várias heuehuehuehue.

    Valeu mesmo

  4. hunter

    Script Ordem de Serviço em Php e Mysql. n tenho condições de pagar um sistema desses e preciso muito de um para meu pequeno negocio.
    existe algum free? xhunterx2009@hotmail.com

  5. Edmilson Britto de Almeida

    Rui Soares, este site ou digamos Blog, é o primeiro em milhares que consulto diariamente e o conteúdo do seu Blog é realmente fantástico, obrigado por compartilhar não so os post mas as experiências vivida como programador, fontes 100% funcional apenas esta um pouco desatualizada devido a função PHP5 mas não complicado vlw…

  6. Artigo muito bom, na minha opinião é o primeiro artigo que trata o tema segurança com exemplos, clareza e segurança. Excelente!!|

  7. Meu nobre amigo,
    suas informações postadas foram de grande auxilio para mim, manterei contado se possível para outras informações e outras dúvidas. Excelente as suas informações

    Abs

    Gilberto Alves

  8. Rony

    Obrigado pelas informações, muito bom!

  9. Olá Eduardo! Obrigado pelo seu comentário! Um Abraço Rui Soares

Participa! Comenta... para Constantine