Inyección de código SQL (SQL injection)


Hoy vamos a ver de que trata esto de las inyecciones SQL y como hacer alguna facilita para que entendamos bien como funciona y los daños que puede provocar. También comentaré rápidamente como podemos protegernos de este ataque en PHP.

Definición

Es una vulnerabilidad informática que consiste en introducir código SQL en las entradas de un sistema, de forma que al usar estas entradas para crear una sentencia SQL ejecute el código inyectado, permitiendo así al atacante conseguir acceso a la aplicación,  manipular la base de datos o incluso ejecutar comandos del sistema.
Esta vulnerabilidad se produce al no validar y filtrar los datos de entrada de una aplicación.

Aplicaciones a las que afecta

A cualquier aplicación hecha con un lenguaje de programación que permita concatenar cadenas de texto, tenga una conexión con un sistema gestor de base de datos SQL como MS SQL,  Oracle o MySQL y que las entradas del usuario se concatenen con sentencias SQL.
Suele ser bastante común este tipo de fallos en aplicaciones web hechas por principiantes, y no tanto, programadas principalmente en php y asp.

Alcance de la vulnerabilidad

Dependiendo del sistema gestor de base de datos y de lo protegida que esté el atacante podrá:

  • Provocar errores en la aplicación. La aplicación puede que muestre el error o no, en caso de que lo muestre es posible que muestre también la consulta que ha fallado o algo de información sobre la base datos dando así a conocer la estructura de esta.
  • Acceder a la aplicación, ya sea como un simple usuario o como un administrador.
  • Consultar, modificar, borrar o insertar datos en la base de datos.
  • Ejecutar comandos del sistema.

Código de ejemplo

Script SQL de la base de datos.

Script PHP para hacer pruebas.

Como podéis ver, el ejemplo tiene un formulario para hacer login con los campos usuario y contraseña, también podemos ver que divido el código  en dos partes:

  1. Método vulnerable, donde veremos cómo aprovecharnos
  2. Método seguro, donde veremos que se hacen bien las cosas.

Este script lo utilizaré como ejemplo de que hay que hacer y que no en las siguientes explicaciones.

Inyectando código SQL

Vamos a probar un poco de qué va esto ¿no? 😀
Fijémonos en la parte del ejemplo  “Método vulnerable” donde hay  varios fallos, a parte de XSS y de que uso la obsoleta API de mysql.
Veamos la sentencia SQL
select id, username, password from usuarios where username='$username' and password='$password'

Sabemos que los datos de entrada van tal y como los introducimos en el formulario y se concatenan directamente con el código SQL así que tenemos vía libre para alargar la sentencia SQL y añadir por ejemplo una condición que siempre se cumple. Veamos.
Si en el campo password introduzco:
' or '1'='1

El código SQL queda:
select id, username, password from usuarios where username='No importa' and password='' or '1'='1'

Al ejecutarse se seleccionan dos filas, todas las de esa tabla, fuera un código de un login “real” existiría una condición para comprobar que se ha seleccionado una fila ¿como hacemos esto?
Vamos a seleccionar un usuario específicamente por ejemplo.
Imaginemos que no sabemos como esta hecha la base datos, si queremos filtrar por un campo necesitamos saber el nombre de la columna del dato a filtrar. Para ello podemos intentar provocar un fallo y ver que pasa.
Simplemente con escribir el carácter ‘ ya podemos hacer que la sentencia SQL se incorrecta. Se imprime el fallo y nos da todos los detalles que necesitamos:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''''' at line 2
select id, username, password from usuarios where username='No importa' and password='''

Ya sabemos la tabla tiene un campo llamado id, vamos a probar con el:
' or id='1
Y efectivamente se selecciona el primer usuario, el administrador.
resultadoSQLinjection

Vosotros diréis: ¡pero que incauto que es este programador!
Pues podría haberlo sido mas aun, os dejo que penséis en esta sentencia SQL:
select id, username, password from usuarios where username like $username and password like $password

Existen otras formas de atacar inyectado código SQL, por ejemplo usando otro tipo de codificaciones como Unicode para saltarse el filtrado o anidando consultas.
También existen programas que ayudan y automatizar esta tarea como sqlmap.

Como evitar en PHP

Para evitar este tipo de ataques hay que:

  • Escapar los caracteres especiales.
  • Filtrar e indicar el tipo de dato.
  • Tener cuidado en donde usas LIKE en una consulta.
  • Asignar los permisos mínimos al usuario de la base de datos que usa aplicación.
  • No mostrar información útil para un atacante cuando se produzca un error.
  • En la parte de ejemplo “Método seguro” se puede ver que uso una API que no esta obsoleta, que uso  el método bindParam para  escapar los caracteres especiales, filtrar e indicar el tipo de dato y que no hace falta usar el LIKE en este caso y no se usa.
  • Para aumentar la seguridad se debería de crear un usuario de mysql con los permisos mínimos y sólo para esta base de datos.
  • También se debería modificar el fichero php.ini para indicar que no se muestren errores. Para ello ponemos modificar la directiva  display_errors  para que quede así:
    display_errors = OFF

Fuentes:

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *