Back-End

31 jul, 2007

Form Injection – Validação de Formuários

Publicidade

Pessoal, vamos falar um pouco de segurança em aplicações WEB? Muito se fala sobre SQL Injection, que é a injeção de comandos SQL numa aplicação WEB através de falhas de segurança. A Injeção desses códigos podem permitir desde a simples mudança de um valor no banco de dados até a exclusão de todas as tabelas do seu banco de dados.

Assim como SQL Injection, há outros tipos comuns de Injections: PHP Injection, Email Injection, Form Injection, etc.

Hoje falarei de Form Injection!

Percebo que pouca gente se liga nesse tipo de ataque! Vamos em frente e você mesmo me dirá se estou certo ou não.

Nosso formulário
<form methos="post" action="cadastra.php">
    <fieldset>
        <legend>Um formulário de Exemplo</legend>
        <input type="hidden" id="cod" name="cod" value="12" />
        <label for="nome">Nome:</label><br />
        <input type="text" id="nome" name="nome" maxlength="30" /><br />
        <label for="senha">Senha:</label><br />
        <input type="password" id="senha" name="senha" maxlength="10" /><br />
        <label for="sexo">Sexo:</label><br />
        <select id="sexo" name="sexo">
            <option value="M">Masculino</option>
            <option value="F">Feminino</option>
        </select><br />
        <input type="submit" id="enviar" name="enviar" value="Enviar' />
    </fieldset>
</form>

Como podem ver, é um formulário bem simples e ingênuo, mas dependendo da sua programação em PHP, pode trazer algumas inconsistências no seu banco de dados, por exemplo.

Suponhamos que esse formulário esteja hospedado em www.meusite.com.br e que o meu código PHP na página cadastra.php está assim:

<?php
    if ( $_SERVER["REQUEST_METHOD"] == "POST" ) {
        foreach ( $_POST as $c => $v ) {
            $c = $v;
        }

        if ( empty( $nome ) || empty( $senha ) ) {
            die("Algum campo está em branco.");
        }

        $sql = "insert into tabela values ($cod,'$nome', '$senha', '$sexo')";

        //Faz a conexão com o banco de dados
        //Executa a query $sql
    }
?>

Como podem ver, verificamos se os campos “nome” e “senha” estão vazios (em branco) e, caso estejam, paramos a execução do nosso script exibindo uma mensagem de erro. Caso não estejam em branco, gravamos os dados no banco de dados.

Caso você nunca tenha ouvido falar em Form Injection, deve estar se perguntando: “E tem alguma coisa errada?”.

A priori, o seu script funcionará bem porque a grande maioria dos usuários são leigos e/ou não estão interessados em causar nenhum tipo de dano.

Mas vamos supor que o usuário malicioso salve o código HTML do formulário na máquina local (máquina do usuário) e faça as seguintes alterações:

<form methos="post" action="http://www.meusite.com.br/cadastra.php">
    <fieldset>
        <legend>Um formulário de Exemplo</legend>
        <input type="hidden" id="cod" name="cod" value="2" />
        <label for="nome">Nome:</label><br />
        <input type="text" id="nome" name="nome" maxlength="50" /><br />
        <label for="senha">Senha:</label><br />
        <input type="password" id="senha" name="senha" maxlength="50" /><br />
        <label for="sexo">Sexo:</label><br />
        <select id="sexo' name='sexo">
            <option value="Zuei o seu site">Zuei o seu site</option>
        </select><br />
        <input type="submit" id="enviar" name="enviar" value="Enviar" />
    </fieldset>
</form>

Está atento? Não? Então vamos às alterações feitas:

  • O action do formulário passou de “cadastra.php” para “http://www.meusite.com.br/cadastra.php”.
  • O campo “hidden” teve o value alterado de 12 para 2.
  • A propriedade maxlength, que parametriza qual a quantidade máxima de caracteres no campo input, do campo “nome” foi alterado de 30 para 50.
  • A propriedade maxlength do campo “senha” foi alterado de 10 para 50.
  • Os options originais do select foram apagados e foi colocado um outro option em seu lugar, com um value muito estranho.

O que aconteceria se o usuário malicioso executasse essa página em seu browser e a submetesse? Alguns erros! No mínimo.

Vamos lá!
  1. Considerando que o campo nome da tabela do banco de dados é varchar(30) e o campo senha varchar(10), o SQL retornaria um erro de dados truncados, caso o mal elemento colocasse uma string de 50 caracteres em cada campo.
  2. Considerando que você tenha colocado o campo sexo da tabela como char(1), também acontecerá um erro na query SQL!

Nesse caso, só aconteceram erros.

Mas e se o malicioso trocasse o value do option de “Zuei o seu site” para “G” e colocasse strings de 10 caracteres nos campos nome e senha?

Ao invés de inserir um registro com código 12, seria inserido com código 2 e pior: com sexo “G”.

Essas são situações simples e que acarretariam poucos danos. Mas essa falha, se bem explorada, pode causar sérios problemas de consistência em sua base de dados.

Vamos à solução?

Na verdade, essa é a maneira como EU faço, mas há outras formas de fazer, obviamente.

<?php
    if ( $_SERVER["REQUEST_METHOD"] == "POST" ) {
        foreach ( $_POST as $c => $v ) {
            $c = $v;
            if ( empty( $v ) ) {
                die( "O campo $c está em branco." );
            }
        }

        $nome = substr($nome, 0, 30);

        $senha = substr($senha, 0, 10);

        if ( $sexo != "M" && $sexo != "F" ) {
            die( "Campo sexo com valor inapropriado." );
        }

        //Faz a validação do campo $cod

        $sql = "insert into tabela values ($cod, '$nome', '$senha', '$sexo')";

        //Faz a conexão com o banco de dados
        //Executa a query $sql
    }
?>
Conclusão

Em suma, para se ver livre do Form Injection assim como outros tipos de Injection, a solução é relativamente simples: basta o desenvolvedor se preocupar em validar todos os dados em que há interação com o usuário!!

Assim, uma boa validação server-side (feita no lado do servidor, ou seja, através de linguagem processada no servidor), resolve a maior parte dos problemas, inclusive esse.

Espero que tenham gostado e que tenham comentários a fazer!

Abraços!