Sunteți pe pagina 1din 4

PHP: Inyección de SQL - Manual http://php.net/manual/es/security.database.sql-injection.

php

Inyección de SQL
Muchos desarrolladores web son desprevendios de cómo las consultas SQL pueden ser manipuladas, y asumen
que una consulta SQL es un comando confiable. Esto significa que las consultas SQL están expuestas a que sean
malversadas en controles de acceso, y por lo tanto, sobrepasar las revisiones de autenticación y autorización
estándar, y que algunas veces las consultas SQL aún podrían permitir el acceso de comandos a nivel de sistema
operativo del ordenador.

Comandos directos de Inyección SQL es una técnica donde un atacante crea o altera comandos SQL existentes
para exponer datos ocultos, sobreponerse a los que son importantes, o peor aún, ejecutar comandos peligrosos a
nivel de sistema en el equipo donde se encuentra la base de datos. Esto se logra a través de la aplicación,
tomando la entrada del usuario y combinándola con parámetros estáticos para elaborar una consuta SQL. Los
siguientes ejemplos están basados en historias reales, desafortunadamente.

Debido a la falta de validación en la entrada de datos y conectándose a la base de datos con privilegios de super
usuario o de alguien con privilegios que puede crear usuarios, el atacante podría crear un super usuario en su
base de datos.

Example #1 Dividiendo el conjunto de resultados en páginas ... y haciendo super usuarios


(PostgreSQL)

<?php

$offset = $argv[0]; // Cuidado, no hay validación en la entrada de datos!


$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";
$result = pg_query($conn, $query);

?>

Los usuarios normales dan clic en los enlaces 'siguiente' o 'atras' donde $offset está codificado en la URL. El script
espera que el $offset entrante sea un número décimal. Sin embargo, qué pasa si alguien intenta irrumpir
añadiendo una función urlencode() al formulario de la siguiente URL
0;
insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd)
select 'crack', usesysid, 't','t','crack'
from pg_shadow where usename='postgres';
--

Si esto sucedió, entonces el script podría presentarle un acceso de super usuario al atacante. Nótese que 0; es
para proveer un offset válido a la consulta original y para finalizarla.

Note:

Esta es una técnica común para forzar al analizador SQL a que ignore el resto de la consulta escrita por el
desarrollador con dos guiónes: -- los cuales representan un comentario en SQL.

Una forma factible de obtener contraseñas es burlar las páginas de búsqueda de resultados. Lo único que el
atacante necesita hacer es ver si hay variables que hayan sido enviadas y sean usadas en declaraciones SQL las
cuales no sean manejadas apropiadamente. Esos filtros pueden ser puestos comunmente en un formulario
anterior para personalizar las cláusulas WHERE, ORDER BY, LIMIT y OFFSET en las declaraciones SELECT. Si su
base de datos soporta el constructor UNION, el atacante podría intentar añadir una consulta enetera a la consulta
original para listar contraseñas de una tabla arbitraria. Utilizar campos de contraseña encriptadoslds es
fuertemente recomendado.

Example #2 Listando nuestros artículos ... y algunas contraseñas (de cualquier servidor de base de
datos)

<?php

$query = "SELECT id, name, inserted, size FROM products

1 de 4 24/01/2011 08:48 a.m.


PHP: Inyección de SQL - Manual http://php.net/manual/es/security.database.sql-injection.php

$query = "SELECT id, name, inserted, size FROM products


WHERE size = '$size'
ORDER BY $order LIMIT $limit, $offset;";
$result = odbc_exec($conn, $query);

?>

La parte estática de la consulta puede ser combinada con otra declaración SELECT la cual revela todas las
contraseñas:
'
union select '1', concat(uname||'-'||passwd) as name, '1971-01-01', '0' from usertable;
--

Si esta consulta (ejecutándose con ' y --) fuera asignada a una de las variables utilizadas en $query, la consulta
reaccionará bestialmente.

Las consultas de actualización de SQL, también son susceptibles a ataques. Estas consultas también son
amenazadas por acortamiento y adición en una consulta completamente nueva a esta. Sin embargo el atacante
podría manipularla con la cláusula SET. En este caso, algunos esquemas de información deben ser procesados
para manipular la consulta exitosamente. Este puede adquirirse examinando la forma de nombres de las
variables, o simplemente forzarlo con un ataque de fuerza bruta. No hay muchas convenciones de nombres para
campos que almacenan contraseñas o nombres de usuarios.

Example #3 Desde re-establecer una contraseña ... hasta ganar más privilegios (en cualquier
servidor de bases de datos)

<?php
$query = "UPDATE usertable SET pwd='$pwd' WHERE uid='$uid';";
?>

Pero un usuario malicioso podría enviar el valor con ' or uid like'%admin%'; -- hacia $uid para cambiar la
contraseña del administrador, o simplemente cambiar $pwd a "hehehe', admin='yes', trusted=100 " (con un
espacio al final) para ganar más privilegios. Entonces la consulta será cambiada así:

<?php

// $uid == ' or uid like'%admin%'; --


$query = "UPDATE usertable SET pwd='...' WHERE uid='' or uid like '%admin%'; --";

// $pwd == "hehehe', admin='yes', trusted=100 "


$query = "UPDATE usertable SET pwd='hehehe', admin='yes', trusted=100 WHERE
...;";

?>

Un ejemplo horrible de cómo pueden ser accedidos los comandos a nivel de sistema operativo en algunos
hospedadores de bases de datos.

Example #4 Atacando el sistema operativo que hospeda la base de datos (Servidor MSSQL)

<?php

$query = "SELECT * FROM products WHERE id LIKE '%$prod%'";


$result = mssql_query($query);

?>

Si un atacante envía el valor a%' exec master..xp_cmdshell 'net user test testpass /ADD' -- hacia $prod, la
consulta $query será:

2 de 4 24/01/2011 08:48 a.m.


PHP: Inyección de SQL - Manual http://php.net/manual/es/security.database.sql-injection.php

<?php

$query = "SELECT * FROM products


WHERE id LIKE '%a%'
exec master..xp_cmdshell 'net user test testpass /ADD'--";
$result = mssql_query($query);

?>

El servidor MSSQL ejecuta la sentencia SQL en el lote que incluye un comando para añadir un usuario nuevo a la
base de datos de cuentas locales. Si esta aplicación estuviera ejecutándose como sa, y el servicio MSSQLSERVER
se está ejecutando con los privilegios suficientes, el atacante ahora podría tener una cuenta con la cual tendría
acceso a esta máquina.

Note:

Algunos de los ejemplos de citados arriba estan vinculados a un servidor de base de datos específico. Esto no
significa que un ataque similar sea imposible en contra de otros productos. Su servidor de base de datos
podría ser vulnerable de forma similar en otra manera.

Técnicas de evación

Podría decir que el atacante debe poseer una proción de información sobre el esquema de la base de datos en la
mayoría de los ejemplos. Tienes razón, pero nunca sabe cuando y cómo esto pueda ser tomado, y si sucede, su
base de datos podría ser expuesta. Si está usando una base de datos de fuente abierta, o un paquete disponible
publicamente, el cual podría pertenecer a un sistema de manejo de contenido o un foro, los intrusos reproducen
facilmente una copia de una porción de su código lo cual podría ser un riesgo de seguridad si esta está
pobremente diseñada.

Esos ataques están principalmente basados en explotar el código que no ha sido escrito teniendo en mente la
seguridad. Nunca confíes en ningún tipo de entrada, especialmente la que viene del lado del cliente, aún cuando
esta venga de una caja de selección, un campo oculto o una cookie. El primer ejemplo muestra que una
inofensiva consulta puede causar desastres.

Nunca se conecte como super usuario o como el propietario de la base de datos. Siempre utilice usuarios
personalizados con privilegios muy limitados.
Revise si la entrada proporcionada tiene el tipo de datos que se espera. PHP tiene un rango amplio de
funciones para validar la entrada de datos, desde las más simples encontradas en Funciones de variable y
en Funciones de tipo Caracter (Ej. is_numeric(), ctype_digit() respectivamente) y siguiendo el apoyo con
las Expresiones regulares compatibles con Perl.

Si la expresión espera una entrada numérica, considere verificar los datos con la función is_numeric(), o
silenciosamente cambie su tipo utilizando settype(), o use su representación numérica por medio de
sprintf().

Example #5 Una forma más segura de redactar una consulta para paginación

<?php

settype($offset, 'integer');
$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";

// Fíjese en %d en el formato de cadena, utilizar %s podría no tener un resultado significativo


$query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET %d;",
$offset);

?>

3 de 4 24/01/2011 08:48 a.m.


PHP: Inyección de SQL - Manual http://php.net/manual/es/security.database.sql-injection.php

Encierre entre comillas cada valor no-numérico provisto por el usuario que sea pasado a la base de datos
filtrado con la función de cadena específica de la base de datos (Ej. mysql_real_escape_string(),
sqlite_escape_string(), etc.). Si una función de escape (o de filtrado) de cadena específica de la base de
datos, o un mecanismo similar no está disponible, las funciones addslashes() y str_replace() podrían ser
útiles (dependiendo del tipo de la base de datos). Vea el primer ejemplo. Como lo muestra el ejemplo,
agregar comillas a la parte estática de la consulta no es suficiente, lo que hace que esta consulta sea
facilmente vulnerada.
No muestre ninguna información específica de la base de datos, especialmente sobre el esquema, por su
correcto significado es como jugar sucio contra usted mismo. Vea también Reporte de errores y Manejo de
errores y funciones de registro.
Podría utilizar procedimientos almacenados y previamente cursores definidos, para abstraer el acceso a
datos para que los usuarios no tengan acceso directo a las tablas o vistas, para que esta solución tenga
otros impactos.

Junto a esto, usted se beneficia de tener un registro de las consultas ya sea dentro de su script o de la base de
datos en si misma, si es que esta soporta el registro. Obviamente, llevar un registro no le previene cualquier
intento de daño, pero éste puede ser útil para hacer una retro revisión de cual aplicación ha sido intervenida. El
registro no es útil por sí mismo, pero lo es debido a la información que contiene. Más detalles generalmente es
mejor que los pocos.

4 de 4 24/01/2011 08:48 a.m.