Underc0de

Programación Web => Back-end => Mensaje iniciado por: Alex en Enero 26, 2013, 12:45:04 PM

Título: Evitar injeccion SQL
Publicado por: Alex en Enero 26, 2013, 12:45:04 PM
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!
Título: Re:evitar injeccion SQL
Publicado por: 2Fac3R en Enero 26, 2013, 02:47:15 PM
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
Título: Re:evitar injeccion SQL
Publicado por: WilyXem en Enero 26, 2013, 06:20:00 PM
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/
Título: Re:evitar injeccion SQL
Publicado por: Alex en Enero 26, 2013, 06:23:41 PM
gracias por la aclaracion 2Fac3r jejeje. lo saqué de un post viejo y no lo miré de nuevo...

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!
Título: Re:evitar injeccion SQL
Publicado por: Once en Enero 26, 2013, 06:42:03 PM
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...

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!

http://php.net/manual/es/function.mysql-real-escape-string.php

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!
Título: Re:evitar injeccion SQL
Publicado por: Alex en Enero 26, 2013, 07:01:24 PM
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...

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!

http://php.net/manual/es/function.mysql-real-escape-string.php

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!
Título: Re:evitar injeccion SQL
Publicado por: WilyXem en Enero 26, 2013, 09:20:33 PM
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!

(http://3.bp.blogspot.com/-SyjwAE2yiGI/T6LZIQi8vlI/AAAAAAAAAU8/jPUDcL1BLLE/s1600/yet_another_picard_facepalm_flip.jpg)

Que tiene que ver MySQL con MySQL(i)=MySQL Injection ?
Título: Re:evitar injeccion SQL
Publicado por: 2Fac3R en Enero 26, 2013, 10:47:33 PM
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
Título: Re:evitar injeccion SQL
Publicado por: Xt3mP en Enero 26, 2013, 10:50:05 PM
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).
Título: Re:evitar injeccion SQL
Publicado por: Alex en Enero 26, 2013, 11:15:09 PM
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!

(http://3.bp.blogspot.com/-SyjwAE2yiGI/T6LZIQi8vlI/AAAAAAAAAU8/jPUDcL1BLLE/s1600/yet_another_picard_facepalm_flip.jpg)

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
Título: Re:evitar injeccion SQL
Publicado por: HckDrk en Enero 26, 2013, 11:51:50 PM
para validar string con solo caracteres alfanuméricos pueden hacer uso de ctype_alnum()

mas info de la función en http://php.net/manual/es/function.ctype-alnum.php

Saludos!
Título: Re:evitar injeccion SQL
Publicado por: Alex en Enero 27, 2013, 12:22:46 AM
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 http://php.net/manual/es/function.ctype-alnum.php

Saludos!

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

saludos!
Título: Re:evitar injeccion SQL
Publicado por: Okol en Enero 27, 2013, 01:20:36 AM
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.
Título: Re:evitar injeccion SQL
Publicado por: Xt3mP en Enero 27, 2013, 06:40:10 AM
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.
Título: Re:evitar injeccion SQL
Publicado por: WilyXem en Enero 27, 2013, 08:48:35 AM
Damn, pues tenias que especificar MySQL improved o injection.
Título: Re:evitar injeccion SQL
Publicado por: Alex en Enero 27, 2013, 11:59:44 AM
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.
Título: Re:evitar injeccion SQL
Publicado por: HckDrk en Enero 27, 2013, 01:16:41 PM
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) [Seleccionar]


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 http://127.0.0.1/archivo.php?search=-1+union+select+1--
nos mostraría lo siguiente: "Búsqueda de 1unionselect1"


o simplemente mostramos un mensaje de error


Código (php) [Seleccionar]

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
Título: Re:evitar injeccion SQL
Publicado por: Alex en Enero 27, 2013, 04:12:13 PM
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) [Seleccionar]


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 http://127.0.0.1/archivo.php?search=-1+union+select+1--
nos mostraría lo siguiente: "Búsqueda de 1unionselect1"


o simplemente mostramos un mensaje de error


Código (php) [Seleccionar]

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 elhacker.net 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!
Título: Re:evitar injeccion SQL
Publicado por: 2Fac3R en Enero 27, 2013, 05:35:31 PM
Ya que están poniendo ejemplos, les dejo unos que tengo desde hace tiempo en PDO:

conexion.php
Código (php) [Seleccionar]

<?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) [Seleccionar]

<?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

http://php.net/manual/es/pdo.constants.php

etc..

Zalu2
Título: Re:evitar injeccion SQL
Publicado por: Alex en Enero 27, 2013, 06:50:54 PM
genial 2Fac3R.

saludos!
Título: Re:evitar injeccion SQL
Publicado por: Okol en Enero 27, 2013, 09:58:57 PM
Muy interesante éste debate.
Muchas gracias Xt3mP Alex y 2Fac3r.
Título: Re:evitar injeccion SQL
Publicado por: ~ Yoya ~ en Febrero 12, 2013, 01:27:37 PM
Sorry por revivir este hilo pero me pareció interesante aportar en este hilo.

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
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/

Lo que muestra en el articulo es un bypass a la mala implementacion de la función mysql_real_escape_string(), eso no quiere decir que mysql_real_escape_string() contenga un bug que se pueda inyectar cualquier consulta SQL. Incluso en el articulo detalla eso, que el bypass esta en la mala implementacion de la función.

Alguien hace mucho tenia la misma duda.

http://foro.elhacker.net/nivel_web/prevencion_de_sqli-t320107.0.html

Sobre lo del PDO y su vulnerabilidad a SQL inyección. No es lo mismo decir que no es vulnerable y entender porque no es vulnerable.

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
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";.

Eso es muy correcto, hay esta la razón porque no suelen ser vulnerables las aplicación ya que en PDO se suelen tratar los datos de entradas para limpiarlos y en MYSQL muchas veces no se tratan los datos de entradas y por eso se dan las SQLI. Pero de igual manera, si no implementas correctamente tu source, un código que utilice PDO y no trate los datos de entradas, seria vulnerable a SQLI.

Saludos.