Seguridad Php (2ª Parte)

Por el 23 de Mayo de 2006

en: Programacion

Cuidado con SQL

Una de las ventajas más grandes de PHP es la facilidad con la cual puede comunicarse con las bases de datos, lo más normal con MySQL . Mucha gente hace el uso excesivo de esto, y muchos grandes sitios, confía en las bases de datos para funcionar.
Sin embargo, con esa ventaja hay problemas suficientemente grandes en la seguridad a los que tendras que hacer frente. Afortunadamente, hay un montón de soluciones. El peligro más común de seguridad al que debes de hacer frente es cuando un usuario utiliza un fallo para poder atacar directamente al servidor de bases de datos con sentencias SQL.
Utilicemos un ejemplo común. Muchos sistemas utilizan un codigo muy parecido a este para comprobar el usuario y la contraseña pudiendose hacer todas las combinaciones válidas del usuario y de su contraseña, por ejemplo para controlar el acceso a un área de administración:

$check = mysql_query(“SELECT Username, Password, UserLevel FROM Users WHERE Username = ‘”.$_POST['username'].”‘ and Password = ‘”.$_POST['password'].”‘”);

¿Te parece familiar? . Y parece que no podría hacer mucho daño. Pero digamos por un momento que introduzco el siguiente ”usuario ” en el formulario:

‘O 1=1 #

La pregunta que va a ser ejecutada sería esta:

SELECT Username, Password FROM Users WHERE Username = ” OR 1=1 #’ and Password = ”

La almohadilla (#) le dice aMySQL que todo que le sigue es un comentario y que no debe de hacerle caso. Ejecutará SQL hasta ese punto. Despues 1 es igual a 1, SQL devolverá todos los usuarios y contraseñas de la base de datos. Y como la primera combinación del usuario y de contraseña en la mayoría de las bases de datos es la de el administrador, la persona que incorporó simplemente algunos símbolos en un formulario ahora entra como administrador de la Web , con los mismos privilegios que tendría si supiera realmente el usuario y la contraseña.

Con una poca de creatividad, este agujero de seguridad se puede explotar aun más lejos, permitiendo que un usuario cree su propia cuenta , lea números de las tarjetas de crédito o simplemente vacie la base de datos.
Afortunadamente, este tipo de vulnerabilidad es bastante fácil de solucionar. Comprobando si hay algun caracter raro cuando el usuario introduce los datos, y quitándolos o neutralizandos, podemos evitar que cualquier persona utilize su propio código del SQL en nuestra base de datos. La función que sigue sería la adecuada:

function make_safe($variable) {
   $variable = addslashes(trim($variable));
   return $variable;
}

Ahora debemos modificar nuestra consulta. En vez de usar variables _POST como en la consulta de arriba, ahora utilizamos todos los datos del usuario con la función make_safe, dando por resultado el código siguiente:

$username = make_safe($_POST['username']);
$password = make_safe($_POST['password']);
$check = mysql_query(“SELECT Username, Password, UserLevel FROM Users WHERE Username = ‘”.$username.”‘ and Password = ‘”.$password.”‘”);

Ahora, si un usuario incorporó los datos anteriormente citados, la consulta será la siguiente, que es totalmente inofensiva. La consulta siguiente seleccionará de una base de datos los registros donde el usuario es igual a “\ ‘O o 1=1 #”.

SELECT Username, Password, UserLevel FROM Users WHERE Username = ‘\’ OR 1=1 #’ and Password = ”

Ahora, a menos que tengas un usuario con un nombre muy inusual y una contraseña en blanco, tu malévolo atacante no podrá hacer ningún daño en tu sitio Web. Es importante comprobar todos los datos pasados a tu base de datos. Las cabeceras de HTTP enviados por elusuario pueden ser falsificadas. Su dirección de remitente tambien puede ser falsificada. No confies en los datos enviados por el usuario, y tu y tu sitio estareis a salvo

10 Respuestas a Seguridad Php (2ª Parte)

Avatar

Anónimo

27 de Julio de 2006 a las 9:37 pm

en el ultimo ejemplo no se concatenaria el or 1=1 (aunq es inofensivo como dices al escapar la ‘),
pero al usar trim() en make_safe() quitara el “or 1=1″ , simplemente queria puntualizar eso

saludos, sk

Avatar

Gustavo

15 de Enero de 2008 a las 8:14 am

Existe otra funcion mejor para escapar caracteres en php que es

mysql_real_escape_string

Ademas si se usa addslashes() hay que verificar si esta activado magic_quotes sino te agrega dobles barras a todo lo que se tome por $_GET, $_POST y todas varibles superglobales

Espero que les sea util
Un cordial Saludo

Avatar

Anónimo

16 de Abril de 2009 a las 9:35 am

Avatar

Anónimo

16 de Abril de 2009 a las 9:35 am

Avatar

Sixto Padron

15 de Octubre de 2009 a las 3:48 pm

Yo valido en Javascript que las cadenas de texto solo acepten Letras, Numeros y en algunos casos . y guiones, asi evito enviarle al servidor datos peligrosos

var reg=/(^[a-zA-Z0-9.]{1,30}).([a-zA-Z0-9.]{1,30}$)/;
if(!reg.test(t))
alert(“Usuario no valido”);

Avatar

Antonio

9 de Noviembre de 2009 a las 4:06 pm

Hola Sixto Padron!

No está mal validar con Javascript en el lado del cliente, pero deberías validar también en el lado del servidor en este caso con PHP. porque si el usuario desabilita Javascript en su navegador, te podría mandar cualquier código malintencionado.

Salu2!

Avatar

Hugo

14 de Noviembre de 2009 a las 12:16 am

Validar con Javascript es un poco riesgoso..ya que basta con desactivar javascript en el navegador para saltarse esa validacion..hay que tener cuidado con eso..

Felicitaciones por la guia esta muy clara, me aclaro unas dudas.
gracias!

Avatar

eLuar

21 de Noviembre de 2009 a las 10:22 pm

Muy buen trabajo… me gustaria comentar que tambien es bueno no solo dejar todo a un solo caballo y tambien poder hacer la validación hacia el lado de la capa de BD ya que podemos mejor hacer marchar un procedimiento almacenado donde se registre la entrada a la BD y en dicho procedimiento lanzar tambien una validación de cada campo antes de ejecutarlo en una consulta, exelentes comentarios a todos

Avatar

Jorge

24 de Noviembre de 2009 a las 10:57 am

tengo una duda pues yo utilizo adodb , para mi aplicaciones con php… bueno no se si este errado pero creo esta linea $check = mysql_query(”SELECT Username, Password, UserLevel FROM Users WHERE Username = ‘”.$username.”‘ and Password = ‘”.$password.”‘”); , no l apuedo usar ya que utedes sabes adodb ultiliza todo genericamente … que me podria servir para utilizarlo con adodb.. realmente lo necesito ..

que me recomiendan

y corrigamen si estoy mal.. gracias

Avatar

Noel

14 de Marzo de 2010 a las 6:44 pm

Ese metodo de trim y demas, para evitar SQL INYECTION, se resume en:
mysql_real_escape_string()

Dejar un comentario

Patrocinadores

¿Interesado en patrocinar TuFunción?

Suscripción

Primera División