Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Andrey Knupp Vital

Filtro de Injection ..

Recommended Posts

  Em 20/12/2010 at 23:51, Beraldo disse:

ok. aquilo foi um exemplo. a execução depende das configurações do servidor e das informações no BD.

a intenção é apenas mostrar que dados numéricos ficam fora de aspas, além de que TODOS os dados devem ser devidamente filtrados e validados

 

Mas e se elas ficarem dentro, também funcionam e mesmo assim ainda dá para fazer SQL Injection?

 

Ps.: Caso positivo, por quê? O mysql_real_escape_string iria "concertar" isso?

Compartilhar este post


Link para o post
Compartilhar em outros sites
  Em 21/12/2010 at 02:12, Marcos Knijnik disse:

Mas e se elas ficarem dentro, também funcionam e mesmo assim ainda dá para fazer SQL Injection?

 

Ps.: Caso positivo, por quê? O mysql_real_escape_string iria "concertar" isso?

elas quem? e dentro de onde?

não entendi

Compartilhar este post


Link para o post
Compartilhar em outros sites

Nossa, realmente o que escrevi não faz sentido...rs

 

Bem, e se eu por as variáveis que irei usar na query em áspas simples, mesmo estas sendo valores numéricos, isso impediria exemplos como os mostrados por vocês?

 

Caso negativo, por quê? E mysql_real_escape_string(), impediria esse tipo de ataque?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Se você ler o manual de mysql_real_escape_string, verá que a função apenas insere barras invertidas. Ela não trata parâmetros de consulta

 

Veja estes testes

mysql> create table numeros(
   -> numero int
   -> );
Query OK, 0 rows affected (0.18 sec)

mysql> insert into numeros(numero) values(7), (42), (73);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from numeros where numero = 7;
+--------+
| numero |
+--------+
|      7 |
+--------+
1 row in set (0.01 sec)

mysql> select * from numeros where numero = '7';
+--------+
| numero |
+--------+
|      7 |
+--------+
1 row in set (0.00 sec)

mysql> create table numeros_decimais( numero decimal(5,2) );
Query OK, 0 rows affected (0.06 sec)

mysql> insert into numeros_decimais values(7.42), (73.07);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> select * from numeros_decimais where numero = 7.42
   -> ;
+--------+
| numero |
+--------+
|   7.42 |
+--------+
1 row in set (0.00 sec)

mysql> select * from numeros_decimais where numero = '7.42';
+--------+
| numero |
+--------+
|   7.42 |
+--------+
1 row in set (0.00 sec)

mysql>

 

Ou seja, mesmo sendo numérico, pode usar aspas. Porém não faz sentido tratar número como string (PHP faz isso, eu sei, mas não faz sentido). Números são números, strings são strings. É importante saber tratar cada um deles de forma adequada, não considerar tudo como string e o BD que se vire

Compartilhar este post


Link para o post
Compartilhar em outros sites

Como o Beraldo já disse, a solução foi proposta por diversas pessoas. Fazendo um resumo:

 

  • Se você espera que o usuário passe uma string, addslashes resolve o problema e independe do SGBD. Também é interessante fazer o Bind dos parâmetros, mas aí depende do SGBD.
  • Se você espera que o usuário passe um número, verifique se é um número (is_numeric()) ou então garanta que é um número, fazendo o cast (intval() ou floatval() ou ainda settype()).

 

Fazendo isto você está seguro de injection.

 

Carlos Eduardo

Compartilhar este post


Link para o post
Compartilhar em outros sites

não, incorreto.

 

veja, sei lá.. tem uma query:

$sql = "SELECT * FROM usuario WHERE id = {$_GET['id']}";

 

se eu fizer um injection assim:

 

$_GET['id'] = ' 0 UNION SELECT * FROM usuario ';

 

a query resultará em:

SELECT * FROM usuario WHERE id = 0 UNION SELECT * FROM usuario

 

ou seja, apenas adicionar as aspas não resolve completamente.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bruno, você leu o tópico? :lol:

 

Não quero ser chato, mas você afirmou que não adianta fazer exatamente o contrário do que eu disse que ia fazer...rs

 

Vamos dizer que eu faça isso:

 

<?php
$str = addslashes($_GET['str']);
$sql = "SELECT * FROM usuario WHERE id = '$str'";

 

Ou seja, mesmo que eu esteja esperando um número, se eu tratá-lo como uma string (mesmo não sendo exatamente uma), olha o que aconteceria caso você tentasse essa injection:

 

$str = '0 UNION SELECT * FROM usuario';
$sql = "SELECT * FROM usuario WHERE id = '0 UNION SELECT * FROM usuario'";

 

E, assim sendo, o que você enviou será tratado como um texto normal, uma string...

 

E então, se eu utilizar addslashes e usar uma string mesmo quando estiver esperando um número já impediria addslashes?

Compartilhar este post


Link para o post
Compartilhar em outros sites
  Em 21/12/2010 at 15:56, Marcos Knijnik disse:

Bruno, você leu o tópico? :lol:

li sim, desde o inicio.

 

 

  Em 21/12/2010 at 15:56, Marcos Knijnik disse:

Não quero ser chato, mas você afirmou que não adianta fazer exatamente o contrário do que eu disse que ia fazer...rs

não.

nesse caso, foi você então que não leu a minha resposta.

 

 

  Em 21/12/2010 at 15:56, Marcos Knijnik disse:

E então, se eu utilizar addslashes e usar uma string mesmo quando estiver esperando um número já impediria addslashes?

essa frase não faz muito sentido, está confusa.

Oque eu te digo é:

apenas addslashes não resolve.

 

teste:

<?php


$id = addslashes( $_GET['id'] );
$sql = "SELECT * FROM usuario WHERE id = {$id}";	
echo $sql;

url:

localhost/?id=0%20UNION%20SELECT%20*%20FROM%20usuario

 

saída:

SELECT * FROM usuario WHERE id = 0 UNION SELECT * FROM usuario

ou seja, uma query válida, e o addslashes não impediu nada.

 

entendeu agora ?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Marcos

 

Olha só.

 

$sql = "SELECT * FROM usuario WHERE id = '$str'";

 

O id é (deve ser) um número inteiro, então ele NÃO DEVE vir entre aspas. Então, vamos imaginar que a $str tenha o valor de 1. A instrução enviada para o banco seria:

SELECT * FROM usuario WHERE id = '1'

Vai funcionar? Vai!!! É correto? NÃO!!!!!!! O correto é que ela fique assim:

 

SELECT * FROM usuario WHERE id = 1

 

Veja, para isto acontecer, o correto é não colocar inteiros entre aspas. Então, no PHP ficaria assim:

$sql = "SELECT * FROM usuario WHERE id = $str";

 

Fazendo como você disse, acontecerá o que o William falou, ou seja, a query fica vulnerável. Agora, se você fizer o CAST para inteiro - como eu sugeri aqui - a query fica segura. Vejamos o que acontece utilizando o exemplo do William:

 

<?php
$id = intval( $_GET['id'] );
$sql = "SELECT * FROM usuario WHERE id = {$id}";        
echo $sql;

URL - localhost/?id=0%20UNION%20SELECT%20*%20FROM%20usuario

 

Saída - SELECT * FROM usuario WHERE id = 0

 

Carlos Eduardo

Compartilhar este post


Link para o post
Compartilhar em outros sites

hum...

 

Mas, Rezende, o que quero fazer é que fique simples...

 

Sempre soube que o certo é não por números como se fossem strings (entre áspas), mas caso o faça resolveria o problema e funcionaria perfeitamente, correto?

Compartilhar este post


Link para o post
Compartilhar em outros sites
  Em 21/12/2010 at 20:42, Marcos Knijnik disse:

...o que quero fazer é que fique simples...

Você acha complicado fazer o cast da variável antes de jogar ela na query? Veja que dá exatamente o mesmo trabalho, só que ao invés de utilizar addslashes, você utiliza intval() ou floatval() (dependendo do tipo de número permitido para aquele campo).

 

  Em 21/12/2010 at 20:42, Marcos Knijnik disse:

Sempre soube que o certo é não por números como se fossem strings (entre áspas), mas caso o faça resolveria o problema e funcionaria perfeitamente, correto?

Resolveria e funcionaria, mas você sabe que está fazendo algo errado. Não é porque funciona que é correto. Veja, você vai fazer o banco de dados trabalhar bem mais para buscar uma string em um local onde só pode ser colocado um número inteiro. Isto é ruim para o desempenho. Para 1 pessoa visitando o site, fazendo 1 consulta, não se percebe a diferença. Mas e se tiver 1.000 pessoas acessando?

 

Carlos Eduardo

Compartilhar este post


Link para o post
Compartilhar em outros sites
  Em 21/12/2010 at 20:42, Marcos Knijnik disse:

Sempre soube que o certo é não por números como se fossem strings (entre áspas), mas caso o faça resolveria o problema e funcionaria perfeitamente, correto?

em um servidor bem configurado não funcionaria, dispararia um erro.

fazendo:

SELECT * FROM usuario WHERE id = '1'

e id sendo um campo do tipo INT, um erro seria disparado, se o servidor estiver bem configurado.

portanto esqueça essa de 'fazendo assim errado funcionaria', pq não funciona!

Compartilhar este post


Link para o post
Compartilhar em outros sites
  Em 21/12/2010 at 20:42, Marcos Knijnik disse:

Sempre soube que o certo é não por números como se fossem strings (entre áspas), mas caso o faça resolveria o problema e funcionaria perfeitamente, correto?

Apenas isto a dizer:

http://desciclo.pedia.ws/wiki/Programa%C3%A7%C3%A3o_Orientada_a_Gambiarras

 

 

Faça como preferir. Você já sabe o que é o certo e o que é o errado. Agora você só precisa decidir.

Um (int) não mata ninguém, muito menos em PHP

 

É importante saber trabalhar com tipos de variáveis. É uma pena o PHP ser tão fracamente tipado. Se um dia você for para Python, por exemplo, terá problemas. Se for para C++/Java, terá sérios problemas.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Ótimo, que bom que a dúvida foi sanada, assim espero, de ante de tantas explicações, não restam dúvidas para o usuário, creio. ^_^

Compartilhar este post


Link para o post
Compartilhar em outros sites

Beraldo...

 

Então será que esse código seria ok?

 

<?php

function anti_injection($campo, $tipo="string"){

    if($tipo == "string"){

         if(get_magic_quotes_gpc() == 0){
              $campo = addslashes($campo);
         }

         return $campo;

    }elseif($tipo=="numeric"){

         if(is_numeric($campo)){
              return $campo;

         }else{
              $campo = preg_replace('/[^0-9]/', '', $campo);
              return $campo;
         }

    }
}

// para realizar a função em caso de sting:
$str = anti_injection($_GET['str']); // irá inserir uma barra invertida antes de ', " e \
echo $str;

// para realizar a função em caso de número:
$num = anti_injection($_GET['num'], "numeric"); // irá excluir todas as letras, espaços e símbulos
echo $num;

?>

Compartilhar este post


Link para o post
Compartilhar em outros sites

Sim, mas se eu estiver esperando um número e o usuário digita algo do tipo '0+and+select...' e eu ver, pelo meio de is_numeric, se o digitado é um número, ele retornará que não é. Ai quando eu for fazer a verificação, eu irei por como se fosse número e não estará seguro...

Compartilhar este post


Link para o post
Compartilhar em outros sites
  Em 22/12/2010 at 17:52, Marcos Knijnik disse:

Sim, mas se eu estiver esperando um número e o usuário digita algo do tipo '0+and+select...' e eu ver, pelo meio de is_numeric, se o digitado é um número, ele retornará que não é. Ai quando eu for fazer a verificação, eu irei por como se fosse número e não estará seguro...

 

se o PHP disser que não é numérico, você não vai colocar como numérico, óbvio.

 

veja:

beraldo@orion:/tmp$ cat teste.php 
<?php
$x = '0+union+select';
echo ( is_numeric( $x ) ? 'É numérico' : 'Não é numérico' ) . "\n";
?>
beraldo@orion:/tmp$ php teste.php 
Não é numérico

 

 

 

 

E sua função dará problema com números do tipo float ou double

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.