Terça-feira, 31 de julho de 2007 às 09h00

Form Injection - Validação de Formuários

Conheça o curso ao vivo: Redes e Protocolos TCP/IP Avançado com Laboratório

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!

6 comentários

 André Mauricio Garcia
31/07/2007 11h08

Bom para o inicio do assunto

...mas de qualquer forma a solução ainda não está nem perto de resolver o problema mais grave que percebi no formulário acima: o uso de campo hidden para trabalhar o id (ou cod) na tabela.
Existem empresas gigantes que tiveram problemas com formulários assim.
É uma prática que deve, no mínimo, ser bem estudada, validar o campo antes e após o envio do formulário e uma solução viável.
A validação pode ser feita por sessão ou pelo método de sua preferência, mas fica o gancho para uma próxima matéria. O assunto é muito interessante e o mais impressionante é que não tem tanta gente que se preocupa com isso, deixando as aplicações vulneráveis a ataques simples.

Parabéns pelo assunto

 Nil Tojal
31/07/2007 12h20

Tenho duvidas

Legal a materia..so não entendi algumas coisas..exemplo...
o cara o pega o codigo do form na sua maquina local.. altera o que quiser tudo bem.. mas como ele consegue depois executar esse codigo no meu site remotamente... ou seja como ele consegue colocar esse codigo no meu site ... se ele não tem senha do ftp ou que seja....
a pergunta pode se banal para alguns ..mas é a minha duvida..abraçosss

 Gustavo Andrade
31/07/2007 13h17

Artigo interessante

Nil, é quando ele altera o "action" do form de cadastra.php para http://www.meusite.com.br/cadastra.php, obtendo o caminho completo, basta executar o arquivo localmente... tmferreira, muito interessante o artigo, mais uma forma de evitar injeção de comando

 Guilherme Rambo
03/08/2007 11h54

Ótimo

Muito bom TM, já sou fã dos seus artigos aqui ;)

 Charles Souza
05/12/2007 11h38

muito bom,

ressucitando o artigo.
thiago está muito seu artigo.
mas voce poderia escrever outro artigo sobre injection, porque esse assunto eh muito importante, apesar de haver muito material na net, nem todos são claros assim, flw

 Thiago Ferreira
05/12/2007 21h47

Resposta ao Charles

Valeu, Charles! E sobre injection de que você está falando?

Cancelar resposta

Qual a sua opinião?

Se você já possui conta iMasters, o login será feito abaixo.

Atenção: comentários considerados spams e/ou ofensivos serão moderados.
Sobre o Autor
Thiago Ferreira mais conhecido como tmferreira (tmferreira@bol.com.br) e é formado em Análise de Sistemas pela Universidade Salgado de Oliveira. Trabalha desde 2005 com desenvolvimento WEB, na FatorClick (http://www.fatorclick.com.br). Também mantém um blog (http://www.tmferreira.com.br/blog/) sobre desenvolvimento WEB, onde escreve sobre PHP, Javascript, Banco de Dados e Webstandards.

2001 - iMasters FFPA Informática Ltda - Todos os direitos reservados.