Protegiendo aplicaciones contra los ataques de inyección SQL
Las inyecciones SQL, son un tema que todo programador debe tener en cuenta, debido a que TODO sistema realizado para acceso Web que interactúe con bases de datos y datos originarios de formularios requiere su atención. No es un tema dificil de entender ya que está ampliamente documentado en la Web. Pero, no obstante, para muchos es un dolor de cabeza, por lo que trataré de reducirles todo a un sencillo y único paso: Filtrar todo dato originario del exterior.
Un ejemplo de como confiar en datos extraños podría desbaratar nuestra lógica, permitiendo comportamientos inesperados, es el siguiente:
// Consultar la base de datos para verificar si hay una coincidencia de usuario
$consulta = "SELECT * FROM usuarios WHERE usuario='{$_POST['username']}' AND password='{$_POST['password']}'";
mysql_query($consulta);
// No revisamos $_POST['password'], ¡podría ser cualquier cosa que el usuario
// quiera! Por ejemplo:
$_POST['username'] = 'admin';
$_POST['password'] = "' OR ''='";
// Esto quiere decir que la consulta enviada a MySQL sería:
echo $consulta;
Por lo que como resultado devolvería
SELECT * FROM usuarios WHERE usuario=’admin’ AND password=” OR ”=”
Permitiendo el inicio de sesión sin una contraseña valida, por lo que recurriremos al tema de…
Filtrado de datos
El proceso de validar los datos e ir dejando fuera datos inválidos, es indiscutiblemente el principio básico de la seguridad en las aplicaciones Web. Una de las prioridades básicas al desarrollar una aplicación Web, es absolutamente simple: Nunca confíes en “ningún” dato extraído del exterior, especialmente información originaria de formularios. (Nunca jamás!)
Registros Globales
En PHP 4.2.0, el valor por default para la directiva register_globals fue cambiado a “off”, sin embargo, aún existen aplicaciones que actualmente funcionan con register_globals (Algunas que tengo por ahí perdidas en mi disco duro
jeje). Actualmente, creo que los desarrolladores de PHP tienen previsto que para la versión 6 de PHP, register_globals haya dejado de ser utilizada completamente por lo que también creo que será eliminada, (No me hagan mucho caso, no me consta).
Cuando activamos la directiva en “On”, register_globals importa datos de diferentes fuentes en el ámbito global de nuestro script. Por ejemplo $_SESSION, $_COOKIE, $_GET, $_POST las define como variables directamente accesibles. Por ejemplo: http://ejemplo/script.php?val1=uno&val2=dos&val3=tres Dentro de script.php, lo correcto sería que mandáramos llamar a los valores de la siguiente forma:
$val1 = $_GET['val1']
$val2 = $_GET['val2']
$val3 = $_GET['val3']
Con register_globals activado, esto ya no es necesario. Podemos tener acceso a las variables directamente de la forma…
echo “$val1 $val2 $val3”;
…y funcionaría correctamente. De igual manera funcionaría si los datos estuvieran en $_POST, $_COOKIE, o $_SESSION (No tengo idea de que pasaría si existieran claves iguales entre $_POST, $_COOKIE, $_GET y $_SESSION. Aunque, hmm… yo me imagino que habría un completo desorden y valores perdidos :-S ).
Aunque este comportamiento es simple y bien documentado, register_globals implica serios problemas durante el filtrado de datos. (Así que ya saben ¡Prohibido usarlo!
)
Ahora, unas cuantas recomendaciones (prácticamente obligadas) para trabajar en servidores con register_globals activados (Y aunque no lo crean, conozco dos servidores públicos que los siguen utilizando, a pesar de las malas críticas:-S ):
- Inicializa siempre todas las variables.
- Desarrolla tus aplicaciones con error_reporting definido en E_ALL.
- Filtra todos los datos que provengan del exterior.
Y ahora si, entrando ya en materia…
Inyecciones SQL (SQL Injection)
Cuando trabajamos con bases de datos, se espera normalmente que ésta interactúe con datos originarios de formularios. Por ejemplo para almacenar datos de un usuario, o simplemente obtener datos a partir de una identidad única.
No obstante la razón, por utilizar datos originarios de formularios posee un muy enorme y comprometedor riesgo. La mayoría de este tipo de vulnerabilidades se debe al resultado del mal filtrado de datos.
Y ahora entrando más profundo en materia… ¿Cómo filtrar los !”#$tos datos?
Si tenemos una consulta de la forma
$sql = “INSERT INTO tabla VALUES ($valor)”;
El riesgo puede disminuirse encerrando con comillas simples el valor.
$sql = “INSERT INTO tabla VALUES (`$valor`)”
Siempre y cuando $valor no contenga comillas simples sin escapar, la consulta SQL puede realizarse con éxito. Sin embargo, esto no es suficiente para asegurar la seguridad de nuestro script, por lo que tenemos que ir más allá del simplemente poner comillas simples. PHP nos ofrece funciones específicas para esta tarea, por ejemplo: En el caso de MySQL pueden confiar ciegamente en mysql_real_escape_string() (Y en otros casos… ya que me entere como se hace, les digo :P).
Links6 Comments
Make A CommentComments RSS Feed TrackBack URL




October 14th, 2006 at 7:32 am
[...] sbado, octubre 14 2006 @ 09:14 ART Las inyecciones SQL, son un tema que todo programador debe tener en cuenta, debido a que TODO sistema realizado para acceso Web que interacte con bases de datos y datos originarios de formularios requiere su atencin. No es un tema dificil de entender ya que est ampliamente documentado en la Web. Pero, no obstante, para muchos es un dolor de cabeza, por lo que tratar de reducirles todo a un sencillo y nico paso: Filtrar todo dato originario del exterior. Un ejemplo de como confiar en datos extraos podra desbaratar nuestra lgica, permitiendo comportamientos inesperados, es el siguiente:Articulo completo: http://www.mis-algoritmos.com/2006/10/13/protegiendo-aplicaciones-contra-los-ataques-de-inyeccion-sql/ — – [...]
October 17th, 2006 at 5:13 pm
strip_tags
(PHP 3 >= 3.0.8, PHP 4, PHP 5)
strip_tags — Elimina etiquetas HTML y PHP de una cadena
http://au2.php.net/manual/es/function.strip-tags.php
November 30th, 2006 at 3:10 pm
Si, también… de hecho ultimamente he investigado más a fondo esto y he coomprendido que es más facil de lo que paréce…
tan reducible a algo como lo siguiente:
function sql_quote( $value ){
if( get_magic_quotes_gpc() )
$value = stripslashes( $value );
if( function_exists( “mysql_real_escape_string”))
$value = mysql_real_escape_string( $value );
// PHP version < 4.3.0 utilizamos addslashes
else
$value = addslashes( $value );
return $value;
}
November 30th, 2006 at 3:12 pm
Gracias zarta por la referencia
December 10th, 2006 at 8:08 pm
[...] Despues de un poco de duda y confusión :-S (Bueno, ni tanto) entre mis conocimientos… [...]
September 1st, 2007 at 2:23 pm
En http://php.net/manual/es/faq.misc.php hay un script para emular Register_globals OFF, asi que ya saben, si en su host las tienen activadas con un include a este script estaran cubiertos.
Saludos.