Evitar injeccion SQL

Iniciado por alexander1712, Enero 26, 2013, 12:45:04 PM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

Enero 26, 2013, 12:45:04 PM Ultima modificación: Marzo 22, 2014, 01:55:49 PM por Expermicid
Este post sale de mi baul de los recuerdos, asique es un poco viejo, pero aún aplica.




Bueno algo muy importante hoy en día al programar en PHP es evitarse una injeccion SQL, ¿como hacemos esto?, filtrando todas las variables que utilizen el $_POST y $_GET.

para filtrarlas podemos usar los comandos

strip_tags
stripslashes
mysql_escape_string

así:

$variable=strip_tags($_POST['algo'];
$variable=stripslashes($variable);
$variable=mysql_escape_string($variable);

y luego ya podemos usar la variable en una consulta a la DB :D




Hola,
El tema de seguridad web es un tema bastante amplio y no se deberia simplemente usar una u otra funcion simplemente para quedarnos tranquilos.
El lema en este tipo de situaciones es bastante sencillo: nunca confies en los datos que manda el usuario, y no solo me refiero a los datos que llegan por $_GET y por $_POST sino tambien cualquier dato que venga en las cabeceras de la peticion http.
La idea en estos casos, es filtrar la informacion y solo recibir los datos que esperamos, se pueden usar expresiones regulares para aumentar la seguridad, pero siempre la seguridad esta dada desde nuestra imaginacion. mas adelante cuando tenga un poco de tiempo realizare tutoriales sobre XSS, RFI, CRSF etc.

para aportar un poco mas sobre estas funciones que nos muestra el compañero alexmanycool

mysql_escape_string es una funcion que en realidad esta deprecada, deberia usarse mysql_real_escape_string en su lugar, esta funcion nos permite filtrar los datos antes de almacenarlos en la base de datos para asi estar mas seguros ante las inyecciones SQL

strip_tags nos permite remover las diferentes etiquetas html del codigo, deberia usarse para filtrar todos los datos de salida, cosa de no cambiar nuestra pagina por voluntad de otro  :¬¬:

htmlentities convierte todos los caracteres a su equivalente html, esto nos permite evitarnos de algunas inyecciones sobre todo de script y html, aunque claro es posible saltarsela, pero nos brinda algo de seguridad




si utilizas algun sistema de noticas o lo que sea y a la variables (ya sea de categoria o de la noticia) la asignas con un numero es decir por ejemplo 1 = noticias 2 = contacto etc...

podrias utilizar la funcion is_numeric() solo va a dejar continuar con la impresion o la ejecucion del script si el valor recibido solo es numerico.

tambien se puede forzar el tipo de dato numérico poniendo

$var = (int)$var;
o
$var = intval($var);

espero les haya sido util

saludos!

Comentar solamente que el strip_tags() y el htmlentities() no son para filtrar inyecciones SQL, sino para evitar XSS (y sus variantes), y de igual forma no son seguras dependiendo el sistema/entorno en que se apliquen.

En caso de que el dato sea string (que son los que más causan problemas) yo recomiendo addslashes() y/o mysql_real_escape_string() [en caso de usar MySQL].

Otra opción bastante fiable es usar PDO.
Buen post!
Zalu2
Sólo el conocimiento te hace libre.

Sabeis que mysql_real_escape_string ha sido bypass-eado ?!

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
My Twitter: No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

|| Security Researcher || Little PenTester || Member of UnderC0de.

One day, You gonna find me, I know that - WilyXem's Motto

Enero 26, 2013, 06:23:41 PM #3 Ultima modificación: Enero 26, 2013, 06:25:50 PM por alexander1712
gracias por la aclaracion 2Fac3r jejeje. lo saqué de un post viejo y no lo miré de nuevo...

Código: php
Sabeis que mysql_real_escape_string ha sido bypass-eado ?!

http://blog.y-shahinzadeh.ir/2012/07/bypassing-mysql_real_escape_string-and-magic_quotes_gpc/


muy interesante, entonces que sugieres para evitar injecciones sql? que no hay forma de evitarlo?

el post habla de forzar el tipo de dato a int que es posible hacerlo también con $result = (int)$variable; pero esto solo aplica a valores numéricos. cuando se refiere a un string como una busqueda, que se podría hacer?

se me ocurre deshabilitar information_schema, pero no se si es posible...

saludos!

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
gracias por la aclaracion 2Fac3r jejeje. lo saqué de un post viejo y no lo miré de nuevo...

Código: php
Sabeis que mysql_real_escape_string ha sido bypass-eado ?!

http://blog.y-shahinzadeh.ir/2012/07/bypassing-mysql_real_escape_string-and-magic_quotes_gpc/


muy interesante, entonces que sugieres para evitar injecciones sql? que no hay forma de evitarlo?

el post habla de forzar el tipo de dato a int que es posible hacerlo también con $result = (int)$variable; pero esto solo aplica a valores numéricos. cuando se refiere a un string como una busqueda, que se podría hacer?

se me ocurre deshabilitar information_schema, pero no se si es posible...

saludos!

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Ahí te lo dice:
CitarEsta extensión está obsoleta a partir de PHP 5.5.0, y será eliminada en el futuro. En su lugar, deberían usarse las extensiones MySQLi o PDO_MySQL. Véase también la guía MySQL: elegir una API y P+F relacionadas para más información. Las alternativas a esta función incluyen:

Saludos!







No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Enero 26, 2013, 07:01:24 PM #5 Ultima modificación: Enero 26, 2013, 07:02:56 PM por alexander1712
No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
gracias por la aclaracion 2Fac3r jejeje. lo saqué de un post viejo y no lo miré de nuevo...

Código: php
Sabeis que mysql_real_escape_string ha sido bypass-eado ?!

http://blog.y-shahinzadeh.ir/2012/07/bypassing-mysql_real_escape_string-and-magic_quotes_gpc/


muy interesante, entonces que sugieres para evitar injecciones sql? que no hay forma de evitarlo?

el post habla de forzar el tipo de dato a int que es posible hacerlo también con $result = (int)$variable; pero esto solo aplica a valores numéricos. cuando se refiere a un string como una busqueda, que se podría hacer?

se me ocurre deshabilitar information_schema, pero no se si es posible...

saludos!

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Ahí te lo dice:
CitarEsta extensión está obsoleta a partir de PHP 5.5.0, y será eliminada en el futuro. En su lugar, deberían usarse las extensiones MySQLi o PDO_MySQL. Véase también la guía MySQL: elegir una API y P+F relacionadas para más información. Las alternativas a esta función incluyen:

Saludos!

en realidad lo más probable es que mysqli también sea bypasseable, PDO no se.

es cierto que toda la rama de mysql_ está deprecated y que se usa mysqli.

es que no me preocupo mucho por ese tipo de cosas, me manejo con una clase que se encarga de hacer las consultas, y utiliza mysqli desde la anteúltima versión.

saludos!

Enero 26, 2013, 09:20:33 PM #6 Ultima modificación: Enero 26, 2013, 09:24:38 PM por WilyXem
Citar


en realidad lo más probable es que mysqli también sea bypasseable, PDO no se.

es cierto que toda la rama de mysql_ está deprecated y que se usa mysqli.

es que no me preocupo mucho por ese tipo de cosas, me manejo con una clase que se encarga de hacer las consultas, y utiliza mysqli desde la anteúltima versión.

saludos!



Que tiene que ver MySQL con MySQL(i)=MySQL Injection ?
My Twitter: No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

|| Security Researcher || Little PenTester || Member of UnderC0de.

One day, You gonna find me, I know that - WilyXem's Motto

Aclarar que cuando uno se refiere a MySQLi es a la extensión MySQL improved no a la inyección.

Por el momento tengo entendido que PDO no es "bypasseable", aunque no estoy muy avanzado en su manejo, se supone que es para la seguridad en consultas de bases de datos.

Zalu2
Sólo el conocimiento te hace libre.

Creo que si lo que quieres evitar es mysql injection, la manera más vieja y fácil es que "castees" a int, como dices, o que valides que la variable tenga un valor numérico exclusivamente (pues en tu caso la inyección se lleva a cabo mediante un ID numérico).
Cada vez que me das Karma me motivas

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
Citar


en realidad lo más probable es que mysqli también sea bypasseable, PDO no se.

es cierto que toda la rama de mysql_ está deprecated y que se usa mysqli.

es que no me preocupo mucho por ese tipo de cosas, me manejo con una clase que se encarga de hacer las consultas, y utiliza mysqli desde la anteúltima versión.

saludos!



Que tiene que ver MySQL con MySQL(i)=MySQL Injection ?

antes de comentar por favor, investiga el tema que se trata.

gracias a todos los demás que comentaron, y xtemp, pero no puedo aplicar eso a un string por ejemplo la busqueda de un nombre :/

saludos

para validar string con solo caracteres alfanuméricos pueden hacer uso de ctype_alnum()

mas info de la función en No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Saludos!

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
para validar string con solo caracteres alfanuméricos pueden hacer uso de ctype_alnum()

mas info de la función en No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Saludos!

eso no creo que ayude mucho a decir verdad :/ no lo se abría que probarlo.

saludos!

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
Aclarar que cuando uno se refiere a MySQLi es a la extensión MySQL improved no a la inyección.

Por el momento tengo entendido que PDO no es "bypasseable", aunque no estoy muy avanzado en su manejo, se supone que es para la seguridad en consultas de bases de datos.

Zalu2
+1 mi bro 2Fact3R

Si no saben de lo que se habla en el tema no se quieran lucir.
Underc0de Manager!

Alex, pues todo depende del concepto y de la plataforma a la cual quieras evitar inyección SQL. Hay distintas maneras para (NO PARCHAR),  sino para hacer más difícil la tarea de ejecutar ésta. Ya sea con PDO, utilizando expresiones regulares para validar lo que se ingresa, utilizando str_replace para eliminar carácteres que no necesitemos, etc... es cuestión del contexto en donde se ejecuta la app. En lo persona, PDO y MySQLimp tienen una buena manera para separar la petición con el parámetro que queremos enviar. De esta manera, si nosotros enviamos, i.e pass' OR 1=1 eso siempre será forzado COMO valor del parámetro, por lo que en teoría SELECT * FROM users WHERE pass = ? quedaría SELECT * FROM users WHERE pass = "pass' OR 1=1";.  Si alguien conoce otra idea, adelante, es bueno debatir respecto a como parchar vulnerabilidades.
Cada vez que me das Karma me motivas

Damn, pues tenias que especificar MySQL improved o injection.
My Twitter: No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

|| Security Researcher || Little PenTester || Member of UnderC0de.

One day, You gonna find me, I know that - WilyXem's Motto

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
Alex, pues todo depende del concepto y de la plataforma a la cual quieras evitar inyección SQL. Hay distintas maneras para (NO PARCHAR),  sino para hacer más difícil la tarea de ejecutar ésta. Ya sea con PDO, utilizando expresiones regulares para validar lo que se ingresa, utilizando str_replace para eliminar carácteres que no necesitemos, etc... es cuestión del contexto en donde se ejecuta la app. En lo persona, PDO y MySQLimp tienen una buena manera para separar la petición con el parámetro que queremos enviar. De esta manera, si nosotros enviamos, i.e pass' OR 1=1 eso siempre será forzado COMO valor del parámetro, por lo que en teoría SELECT * FROM users WHERE pass = ? quedaría SELECT * FROM users WHERE pass = "pass' OR 1=1";.  Si alguien conoce otra idea, adelante, es bueno debatir respecto a como parchar vulnerabilidades.

la verdad te agradezco, me haz dado una idea, lo de las expresiones regulares, jamás se me ocurrió utilizarlo de éste modo, porque a decir verdad prefería pensar que con mysql_real_escape_string era suficiente xD es muy interesante lo que propones, como siempre, haz dicho algo muy interesante, no se puede esperar menos de xt3mp.

CitarDamn, pues tenias que especificar MySQL improved o injection.

mejor dejalo así, peor por la temática y por la forma en que se estaban diciendo las cosas, si sabes del tema, no hacen falta aclaraciones.

en fin, un saludo para todos! y esta es realmente un debate muy interesante, si alguno tiene otras ideas que las comente, siempre y cuando no intente dejar a nadie como tarado, que realmente no aporta en nada.

bueno XD

aquí les dejo unos ejemplos de como se podría evitar con ctype_alnum()

una forma seria eliminando cualquier carácter que no sea alfanumérico...

Código: php
	

function limpiar($cadena){

for($i=0;$i<strlen($cadena);$i++){
if(ctype_alnum($cadena[$i])){
$cadena_l.=$cadena[$i];
}
}

return $cadena_l;
}


echo "Busqueda de <b>".limpiar($_GET['search'])."</b>";


así si intentamos una inyección de esta forma No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
nos mostraría lo siguiente: "Búsqueda de 1unionselect1"


o simplemente mostramos un mensaje de error


Código: php

if(ctype_alnum($_GET['search'])){
echo "Busqueda valida de <b>".strip_tags($_GET['search'])."</b>"; //ya no haria falta la funcion strip_tags, ya que con ctype_alnum() valida si contiene otros caracteres, sino muestra error, pero es costumbre y no va de mas un poco mas de seguridad XD
}else{
echo "Error! Busqueda(query, consulta, etc.) invalida!";
}


asi si introducimos alguna inyección nos mostrara error.

bueno, esta es mi forma en que evitaría un sqli, tal vez no sea la mejor forma, cada quien tiene sus métodos, en fin...

Saludos!  ;D

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
bueno XD

aquí les dejo unos ejemplos de como se podría evitar con ctype_alnum()

una forma seria eliminando cualquier carácter que no sea alfanumérico...

Código: php
	

function limpiar($cadena){

for($i=0;$i<strlen($cadena);$i++){
if(ctype_alnum($cadena[$i])){
$cadena_l.=$cadena[$i];
}
}

return $cadena_l;
}


echo "Busqueda de <b>".limpiar($_GET['search'])."</b>";


así si intentamos una inyección de esta forma No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
nos mostraría lo siguiente: "Búsqueda de 1unionselect1"


o simplemente mostramos un mensaje de error


Código: php

if(ctype_alnum($_GET['search'])){
echo "Busqueda valida de <b>".strip_tags($_GET['search'])."</b>"; //ya no haria falta la funcion strip_tags, ya que con ctype_alnum() valida si contiene otros caracteres, sino muestra error, pero es costumbre y no va de mas un poco mas de seguridad XD
}else{
echo "Error! Busqueda(query, consulta, etc.) invalida!";
}


asi si introducimos alguna inyección nos mostrara error.

bueno, esta es mi forma en que evitaría un sqli, tal vez no sea la mejor forma, cada quien tiene sus métodos, en fin...

Saludos!  ;D

si funcionaría bien como int, pero volvamos al ejemplo de una búsqueda que es la misma razon por la que no se puede usar int, si la persona busca con espacios ya no funcionará la busqueda, si la persona busca algo así como los angeles de charly [FULLDVD] tampoco le buscará...

me explico?

para todo lo demás se puede usar la sencilla técnica de No tienes permitido ver los links. Registrarse o Entrar a mi cuenta que crea urlseo y utiliza el id únicamente (pasado por int) para obtener el registro, mientras que el resto es simplemente decoración o seo.

saludos!

Ya que están poniendo ejemplos, les dejo unos que tengo desde hace tiempo en PDO:

conexion.php
Código: php

<?php
   
    function conectar(){
$dsn = 'mysql:host=localhost; dbname=test;';
$user = 'root';
$pwd = 'toor';
    $con = new PDO($dsn,$user,$pwd);

return $con;
}
?>


Un pequeño sistema de noticias (muy feo por cierto xD):

Código: php

<?php

require_once('conexion.php');

try{

$con = conectar();
$id = $_GET['id'];

$query = $con -> prepare("SELECT * FROM noticias WHERE id=:id");
$query -> bindParam(':id',$id,PDO::PARAM_INT,1);
$query -> execute();

foreach($query as $value){
echo $value['titulo'].'<br>';
echo $value['detalle'].'<br>';
echo $value['autor'].'<br>';
}
}catch(PDOException $e){
die($e->getMessage());
}
?>


Podemos expecificar datos, por ejemplo:

PDO::PARAM_STR
PDO::PARAM_INT

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

etc..

Zalu2
Sólo el conocimiento te hace libre.