Palavra:   

Revista PHP / Segurança

Anderson Dias

Evitando injection em formulário web com PHP

Interações entre formulários web e usuários deixam uma porta aberta para inserção de qualquer tipo de dado. Essa possibilidade pode ser ao mesmo tempo o céu ou inferno de um desenvolvedor. Formulários que não possuem controle de dados de entrada correm o sério risco de serem manipulados indevidamente, prejudicando a segurança do sistema.

Injections são uma forma de manipulações mal intencionadas de formulários web e podem atingir desde funções em linguagem de programação até manipulações em banco de dados, correndo o risco de danificar o sistema ou expor dados privados.
Uma maneira de contornar este problema é tratar todos os dados de entrada, independente de qual tipo de componente de formulário ele teve origem.

Como as passagens de dados de uma página para outra é feita através de vetores (POST, GET, SESSION, COOKIE) todos estes vetores devem ser verificados antes dos seus dados serem utilizados.

O primeiro passo é definir uma função que elimine toda entrada de formulário considerada maliciosa, que de uma forma ou de outra poderia prejudicar o sistema. As entradas mais comuns são espaços vazios, configuração de cabeçalho de e-mail como Content-Type e bcc, tags HTML como os sinais de maior e menor, e aspas. Para contornar este problema criamos a seguinte função:
PHP
  1. /**
  2. * @abstract Tratamento de injections em formulários.
  3. * @return string
  4. */
  5. function antiInjection($str)
  6. {
  7. # Remove palavras suspeitas de injection.
  8. $str = preg_replace(sql_regcase("/(\n|\r|%0a|%0d|Content-Type:|bcc:|to:|cc:|Autoreply:|from|select|insert|delete|where|drop table|show tables|#|\*|--|\\\\)/"), "", $str);
  9. $str = trim($str); # Remove espaços vazios.
  10. $str = strip_tags($str); # Remove tags HTML e PHP.
  11. $str = addslashes($str); # Adiciona barras invertidas à uma string.
  12. return $str;
  13. }
  14.  
www.revistaphp.com.br
Esta função remove possíveis entradas de dados maliciosas. Tem como parâmetro de entrada um vetor, podendo ser qualquer vetor, desde vetores criados pelo próprio desenvolvedor até vetores próprios da linguagem, como POST, GET, COOKIE e SESSION.

Com a função de tratamento de injection criada, caímos em outro problema: pode haver vetores dentro de vetores. Um exemplo disto seria um select multiple ou um vetor de checkbox. Para tratar isto criamos outra função:
PHP
  1. /**
  2. * @abstract Antes de tratar os injections, verifica se é vetor ou não.
  3. */
  4. function validaParametro($vetor)
  5. {
  6. if (is_array($vetor))
  7. {
  8. foreach ($vetor as $chave => $valor)
  9. {
  10. if (is_array($valor))
  11. {
  12. $vetor[$chave] = validaParametro($valor);
  13. } else $vetor[$chave] = antiInjection($valor);
  14. }
  15. } else $vetor[$chave] = validaParametro($valor);
  16. return $vetor;
  17. }
  18.  
www.revistaphp.com.br
Dessa forma, antes de tratar possíveis injections, verifica se o parâmetro passado é um vetor ou não, caso seja um vetor, a função validaParametro() é chamada recursivamente passando o novo vetor como parâmetro, caso não seja um vetor, chama a mesma função passando a string a ser tratada. A chamada à função ficaria da seguinte forma:
PHP
  1. $_POST = validaParametro($_POST);
  2. $_GET = validaParametro($_GET);
www.revistaphp.com.br

Lembrando que qualquer vetor pode ser verificado.

Opções de Interação

Comentários

Resposta para Andre
Por: Anderson, 27/06/2008   09:18:40
André, a senha é um campo comum de texto, como outro qualquer. O script que criei irá procurar por códigos maliciosos em qualquer campo dentro do formulário, incluindo "senhas" (que nada mais são do que um campo comum de formulário, o tratamento que você dá à elas é o que as diferencia).

Se sua aplicação permite algum código malicioso como senha, ela está vulnerável. Minha sugestão é: limite as possibilidades de combinação de caracteres para senha, de forma que torne a senha segura (complexidade) sem que permita combinações que possam gerar códigos maliciosos.

Lembrando que esta função trata apenas alguns códigos maliciosos, pode ser adaptada para qualquer caso.

Um abraço.
Anderson Dias
Valeu pela dica mas..
Por: andre, 27/06/2008   09:09:36
Eu sou novo no uso e prática do PHP, mas e no caso de um formulário q possua a inserção da senha de validação a pagina, esse antiInjection ñ iria suspeitar dela caso o usuario final inconscientemente inserir algum dado malicioso? a senha do indivíduo seria aceita do mesmo jeito ou ia causar alguma mudança por ordem do sistema mesmo usando o comando MD5('senha') q "Criptografa" a senha?
Boa dica
Por: Daniel, 15/06/2008   14:46:31
realmente as vezes não percebemos como uma simples instrução sql pode danificar toda uma tabela de usuarios ou ate mesmo pontos mais criticos do sistema, seja ela "atacada" de forma proposital ou por pura ingenuidade do usuário.

otima dica ...
Muito Bom...
Por: Manoel, 10/06/2008   02:02:47
Essa deve ser uma preocupação rotineira na vida de programadores, mais é interessante notar-se que hoje não temos só problemas com sql injection, temos também php injection, form injection, ajax injection e possíveis brechas em nossos servidores web. A verdade é que não é difícil evitar todos esses problemas, sei que nada é 100% seguro, porém, manter-se atualizado e atualizar nossos servidores sempre vão garantir maior segurança e com certeza menos trabalho concertando estragos por ataques e perdas e inconsistência de dados.
Legal
Por: Julien, 03/04/2008   14:46:18
Funciona, mas este aqui é bem mais simples ....

http://murray.livreforum.com/php-f4/script-anti-sql-inject-t14.htm