Siga-nos em...
Follow us on Twitter Follow us on Facebook Watch us on YouTube
Registro

Alpha Servers
Resultados 1 a 10 de 12

Visão do Encadeamento

  1. #1

    Avatar de 14biss
    Data de Ingresso
    Jul 2010
    Localização
    Maceió
    Idade
    29
    Posts
    129
    Agradecido
    12
    Agradeceu
    8
    Peso da Avaliação
    17

    Padrão Evitando SQL Injection usando Prepared Statements - PHP+PDO

    Uma das maiores vulnerabilidades de sites, a injeção de SQL ([Somente usuários registrados podem vem os links. ]) é também, no caso do PHP, uma das mais fáceis de prevenir. Infelizmente, muitos não tomam as devidas precauções e acabam tendo os seus dados comprometidos.

    SQL Injection
    Antes de começar, vale a pena ilustrar como funciona um ataque típico de SQL Injection:
    Código PHP:
    // Temos esta consulta simples aonde os dados $username e $password vem de um formulário preenchido pelo usuário
    $query "SELECT * FROM tabela WHERE username = '$username'";
     
    // Se não houver validação correta um usuário mal-intencionado poderia colocar algum código SQL no lugar do username:
    $username "' OR 1'";
     
    // A consulta ficaria assim:
    $query "SELECT * FROM tabela WHERE username = "'' OR 1";
     
    // Como a expressão 'OR 1' sempre resulta em TRUE, a consulta retornaria os dados de todos os usuários no sistema 
    Convenhamos, o exemplo acima é bobo, mas serve para mostrar a teoria por trás da técnica de injeção de sql. Se ainda não se convenceu de que é necessário, veja um exemplo mais grave:
    Código PHP:
    // começamos com a mesma consulta
    $query "SELECT * FROM tabela WHERE username = '$username'";
     
    // desta vez, o código inserido é bem mal-intencionado mesmo...
    $username "'; DELETE FROM tabela WHERE 1 OR username = '";
     
    // a consulta final ficaria assim:
    $query "SELECT * FROM tabela WHERE username = ''; DELETE FROM tabela WHERE 1 OR username = ''";
     
    // ou seja, se executada, a consulta excluiria todos os registros da tabela 
    Validação sozinha não resolve!

    Você pode estar questionando se uma boa validação já não resolveria o problema, já que em ambos exemplos validar para aceitar somente letras funcionaria para bloquear ambas tentavas. Bom a resposta é: SIM e NÃO!

    Por mais que a validação ajude, mesmo usando expressões regulares complexas, há meios de burlá-la utilizando outros charsets e técnicas maliciosas. Segurança nunca é demais e não custa se prevenir para proteger os seus dados ou os dos seus clientes.

    O que são prepared statements?

    Nada mais são do que consultas “pré-prontas”… A diferença é que em lugar das variáveis você coloca um placeholder (marcador de lugar) e na hora da consulta informa a ordem das variáveis a serem substituidas.

    É mais fácil de explicar com um exemplo:
    Código PHP:
    // a interrogação vai no lugar da variável
    $query "SELECT * FROM tabela WHERE username = ?";
     
    // para fazer com vários parametros é a mesma coisa
    $query "SELECT * FROM tabela WHERE username = ? OR username = ?"
    Depois, é só informar o que vai no lugar dos respectivos ‘?’ e a consulta estará protegida! Isto funciona porque ao prepararmos a consulta, avisamos ao MySQL (ou outro [Somente usuários registrados podem vem os links. ] que suporte prepared statements) como é a consulta e exatamente aonde vão as variáveis. Repare que nem precisamos mais colocar aspas em volta da variável, pois ele já sabe que é uma variável e a trata de acordo.

    No PHP, a extensão [Somente usuários registrados podem vem os links. ]também suporta statements preparados, mas recomendo sempre utilizar o PDO pois ele facilita a migração para outros bancos, além de oferecer uma API concisa entre eles.

    Como Funciona com PDO
    Código PHP:
    // vamos partir do pressuposto que temos um objeto PDO instanciado e devidamente configurado e iremos trabalhar com a mesma consulta dos exemplos anteriores
    $query "SELECT * FROM tabela WHERE username = ?";
     
    // o método PDO::prepare() retorna um objeto da classe PDOStatement ou FALSE se ocorreu algum erro (neste caso use $pdo->errorInfo() para descobrir o que deu errado)
    $stmt $pdo->prepare($query);
     
    // agora que temos o statement preparado, precisamos "bindar" a variável
    $username "fulano";
     
    // utilizamos o método PDOStatement::bindValue() que aceita como parâmetros a posição do ? que a variável irá substituir (a primeira é 1) e a própria variável
    $stmt->bindValue(1$username);
     
    // executamos o statement
    $ok $stmt->execute();
     
    // agora podemos pegar os resultados (partimos do pressuposto que não houve erro)
    $results $stmt->fetchAll(PDO::FETCH_ASSOC); 
    Parece meio chato, ter que escrever tanto código a mais para executar uma simples consulta e se a questão da segurança não for motivo sufiente, que tal este: statements preparados são mais rápidos que consultas normais! Especialmente se a mesma consulta for executada diversas vezes durante um request (mudando ou não as variáveis).

    Como o assunto é extenso, incluirei algumas informações adicionais para esclarecer alguns itens, se não precisar de tanto detalhe técnico pode pular ao final!

    Informações Complementares

    • Há outro método para fazer “bind” das variáveis: o PDO::bindParam(), a síntaxe é exatamente a mesma mas ele recebe a variável por referência, enquanto PDO::bindValue() recebe por valor.
      .
    • Tanto o bindValue() quanto o bindParam() aceitam um terceiro parâmetro opcional que é o tipo da variável (PDO::PARAM_STR, PDO::PARAM_INT, etc)
      .
    • Se não gostou da sintaxe de colocar varias interrogações e depois substituir as variáveis de acordo com a posição da interrogação, também é possível utilizar placeholders nomeados:

    Código PHP:
    // em vez da interrogação utilizamos uma palavra prefixada de um ":"
    $query "SELECT * FROM tabela WHERE username = :usuario OR username = :administrador";
     
    // na hora de fazer bind fica mais claro qual variável vai aonde
    $stmt->bindValue(":usuario"$username);
    $stmt->bindValue(":administrador""admin");
     
    // este método também facilita fazer binds dentro de loops foreach aonde o placeholder é a chave e a variável é o valor
    foreach($variaveis as $k => $v){
        
    $stmt->bindValue(":$k"$v);

    E lembre-se, ignorar estas dicas na hora de criar um sistema é o famoso caso do “barato que sai caro”.
    Última edição por 14biss; 02-06-2011 às 12:28 AM.

    break $this->Fuck();

 

 

Informações de Tópico

Usuários Navegando neste Tópico

Há 1 usuários navegando neste tópico. (0 registrados e 1 visitantes)

Tópicos Similares

  1. |Tutorial| Tutorial SQL Injection Avançado
    Por Hazid no fórum Tutoriais
    Respostas: 6
    Último Post: 29-07-2012, 07:48 PM
  2. |Tutorial| Evitando trade bug's ou como dizem o famoso trade hacker!
    Por Cøłєridgє no fórum Tutoriais, dicas e macetes
    Respostas: 1
    Último Post: 23-08-2010, 12:01 AM
  3. |Tutorial| Evitando Bug Desconnect Por Players
    Por vinnymga no fórum Servers
    Respostas: 0
    Último Post: 19-02-2010, 05:20 PM
  4. |Tutorial| Evitando ataques de SQL Injection
    Por mend3 no fórum PHP
    Respostas: 0
    Último Post: 29-10-2009, 04:20 PM
  5. |Tutorial| Usando Telnet
    Por mend3 no fórum L2J | Tutoriais
    Respostas: 2
    Último Post: 14-09-2009, 02:38 PM

Marcadores

Permissões de Postagem

  • Você não pode iniciar novos tópicos
  • Você não pode enviar respostas
  • Você não pode enviar anexos
  • Você não pode editar suas mensagens
  •