Evitar Inyección SQL (II)
Escrito por J.F. el Jueves, 6 de Septiembre del 2007 a las 22:00
Una vez visto en qué consiste la Inyección SQL y cuales pueden ser sus graves consecuencias, vamos a explicar algunos métodos para evitar dicho peligro, mediante la implementación de diferentes métodos. En general daré soluciones en concreto para PHP, pero son aplicables a otro tipo de lenguajes como ASP o JSP, aunque también trataré de dar alguna pequeña ayuda para los que usen éstos lenguajes. Vamos allá en principio, con las soluciones para PHP:
Aunque hay varias formas de protegerse contra la Inyección SQL en PHP, yo tan sólo voy a recomendar una serie de reglas generales a seguir:
Utiliza siempre las comillas simples (') para delimitar las variables que vayas a usar en una consulta a la base de datos. De esa manera la posibilidad de Inyección SQL se ve reducida de forma considerable:
-
SELECT usuario FROM indentificacion WHERE usuario= ' $usuario ';
Realiza las validaciones pertinentes para verificar el tipo que debe tener una variable. Ésto puedes realizarlo en el lado del cliente mediante el uso de Javascript, o bien por parte del servidor utilizando PHP. Aunque Javascript es recomendable, no puede ser 100% eficiente, por lo que es recomendable realizar siempre la validación al menos en el lado del servidor, y nunca depender unicamente de Javascript. Es decir, si en un campo esperas obtener un número, comprueba que sea un número, no confíes en el "buen hacer" del usuario. Para ello puedes utiizar en PHP la función gettype(), que devuelve el tipo de la variable.
Evita el uso del operador asterisco (*), si deseas obtener 2 campos de una tabla, a pesar de que dicha tabla no contenga más que esos 2 campos trata de evitar el uso del asterisco(*). Imagina que posteriormente a la tabla sobre la que realizas una consulta se le añaden nuevos campos, estarías cargando información que no es encesaria, y dichos datos que no son utilizados para nada podrían ser obtenidos mediante una Inyección SQL. Además, seleccionar campos que no vas a utilizar posteriormente es aumentar el uso de memoria y de banda ancha del servidor, ralentizando la aplicación.
Puede ser que tengamos configurado nuestro servidor para que cambie las comillas de las variables pasadas, según leo en ProgramaciónWeb.net ejecutando el siguiente código podremos saber si nuestro servidor tiene activado dicho nivel de seguridad en función del mensaje mostrado en pantalla:
Si la prueba dice que somos vulnerables, quiere decir que la comilla simple(') no es cambiada por (\'). Para solucionar éste hecho proponen el siguiente script para "limpiar" las variables pasadas tanto por URL como por formulario:
inyeccion.php
-
<?
-
// Evitamos la inyeccion SQL
-
-
// Modificamos las variables pasadas por URL
-
foreach($_GET as $variable=>$valor){
-
}
-
// Modificamos las variables de formularios
-
foreach($_POST as $variable=>$valor){
-
}
-
?>
Luego tan sólo será necesario incluir el fichero en toda página que realicemos querys contra la base de datos:
-
<?
-
// Evitamos la inyeccion SQL
-
include 'inyeccion.php';
-
//
-
// Contenido de la página PHP
-
//
-
?>
Éste método es totalmente válido, aunque más tarde veremos otros métodos que yo al menos prefiero y son más eficaces.
Otro consejo, en éste caso de caracter general, es utilizar un único usuario para realizar todo tipo de consultas, y no utilizar como mucha gente hace el usuario root(administrador de la base de datos), ya que la que se puede armar es gorda.
La función que recomiendo, siempre que estemos programando en PHP y utilicemos la base de datos MySQL(es bastante común) es mysql_real_escape_string($parametro), que corrije la inserción de caracteres que puedan dar lugar a Inyección SQL, dejando "limpia" la variable que le pasamos. Aquí teneis un ejemplo tal y como indica la Wikipedia:
-
$query_result = mysql_query
-
(
-
"SELECT * FROM usuarios WHERE nombre = \""
-
.
-
mysql_real_escape_string($nombre_usuario)
-
.
-
"\""
-
);
Por último no debemos olvidar mencionar la función get_magic_quotes_gpc(), que se utiliza también para el filtrado de comillas. Según propone Mis-Algoritmos aquí teneis una función para filtrar una cadena antes de emplearle en la consulta contra la base de datos. La función en cuestión es la siguiente:
-
function sql_quote($value){
-
-
//check if this function exists
-
else//for PHP version <4.3.0 use addslashes
-
-
return $value;
-
}
La forma de utilizarla, según el propio autor comenta es la siguiente:
-
$password = sql_quote($_POST['password']);
Como vemos utiliza bien el entrecomillado en las variables, pero recordemos que debemos evitar el uso del asterisco (*) en medida de lo posible.
Dejando de lado PHP en concreto, también podemos utilizar la función replace de Visual Basic para eliminar caracteres no deseados. Un ejemplo de Maestros del Web.
-
SSQL= "SELECT count(*) FROM Usuarios WHERE Usuario = '" & ReplacetxtUsuario.Text, "’", "”") & "’ AND password=’" & Replace(txtPassword.Text, "’", "”") & "’"
Según comentan en Maestros del Web, otra solución definitiva sería crear un procedimiento almacenado, de modo que la inyección SQL queda anulada. Proponen el siguiente código:
CREATE Procedure Validar @usuario varchar(50), @password varchar(50)
ASIf (SELECT Count(*) FROM Usuarios WHERE Usuario=@Usuario and Password=@password)>0Return 1Return 0
Para Java, según la Wikipedia de nuevo, deberemos utilizar la clase PreparedStatement:
En lugar de
-
ResultSet rset = stmt.executeQuery("SELECT * FROM usuarios WHERE nombre = '" + nombreUsuario + "';");
deberemos utilizar:
-
pstmt.setString(1, nombreUsuario);
Con ésta serie de procedimientos doy por revisado algunos consejos generales y algunos métodos para evitar la Inyección de SQL en distintos tipos de lenguajes. Hay muchas más funciones y scripts por Internet que se adecuarán mejor o peor en función de tu situación específica, asi que si crees que con lo visto en éste artículo no hay suficiente no dudes en seguir buscando por Internet. Para terminar, mañana veremos algunas herramientas y métodos para buscar vulnerabilidades en nuestro código SQL, además de algunos cuantos enlaces sobre el tema que nos vendrán de perlas.
Categoria: General
- Añadir este post a
- Del.icio.us -
- Meneame -
- Digg -
- Webeame
Entradas relacionadas
Comentario de PerroVerd
Realizado el Viernes, 7 de Septiembre del 2007 a las 18:02
Una forma más sencilla de evitar la inyección en PHP, al menos si tenemos la versión 5, es usar las librerías estándar PDO y sus ¿sentencias preparadas? (prepared statements). http://es.php.net/pdo
Comentario de J.F.
Realizado el Viernes, 7 de Septiembre del 2007 a las 19:09
Muchas gracias por el apunte, conocía otra librería que olvidé postear(http://pear.php.net/package/DB), pero ésta no.
Un saludo.
Comentario de Marcelo
Realizado el Miércoles, 7 de Noviembre del 2007 a las 20:19
muchas gracias!, es buenos saber que existe lugares donde uno comparte su conocimiento y asi avanzamos en la construccion del conocimiento de cada uno de nosostros.
Comentario de J.F.
Realizado el Sábado, 10 de Noviembre del 2007 a las 14:05
Claro amigo, ésta es la gracia de Internet. Compartir ![]()
Saludos.
Comentario de Luis
Realizado el Miércoles, 13 de Febrero del 2008 a las 1:46
Se os ha olvidado indicar que mysql_real_escape_string() no filtra los comodines en caso de trabajar con el comparador de cadenas LIKE. Me estoy refiriendo al simbolo del tanto por ciento (%) y el guion inferior (_). No permiten inyectar SQL, pero en caso de búsquedas, permite al usuario malintencionado lanzar consultas más genéricas, con el impacto que ello pueda tener en el rendimiento.
Harina de otro costal es el uso del LIKE en las búsquedas existiendo las búsquedas a texto completo (fulltext), pero esa ya es otra historia.
Comentario de J.F.
Realizado el Lunes, 18 de Febrero del 2008 a las 17:19
Gracias por el apunte Luis ![]()
Un saludo.
