¿Qué es la inyección de código SQL (SQi)?
La inyección de código SQL* (Structured Query Language) es una técnica de inyección de código que se utiliza para modificar u obtener datos de bases de datos SQL. Mediante la inserción de sentencias SQL especializadas en un campo de entrada, un atacante puede ejecutar comandos que permitan obtener datos de la base de datos, destruir datos confidenciales u otras manipulaciones.
Con la ejecución de comandos SQL adecuada, el usuario no autorizado es capaz de suplantar la identidad de un usuario con más privilegios, convertirse a sí mismo o a otros en administradores de la base de datos, manipular los datos existentes, modificar las transacciones y los balances, y recuperar o destruir todos los datos del servidor.
En la informática moderna, la inyección de código SQL suele producirse a través de Internet mediante el envío de consultas SQL maliciosas a un punto final de la API proporcionado por un sitio web o un servicio (más información al respecto más adelante). En su forma más grave, la inyección de código SQL puede permitir que un atacante consiga acceso raíz a una máquina, lo que le da el control total.
*SQL es un lenguaje de programación usado para mantener la mayoría de las bases de datos.
¿Cómo funciona un ataque de inyección de código SQL?
Imaginemos una sala de un tribunal en la que un hombre llamado Bob está siendo juzgado y está a punto de comparecer ante el juez. Al rellenar los papeles antes del juicio, Bob escribe su nombre como "Bob es libre de irse". Cuando el juez llega a su caso y lee en voz alta "Llamamos a Bob es libre de irse", el alguacil deja ir a Bob, porque eso es lo que ha dicho el juez.
Aunque hay variedades ligeramente diferentes de SQLi, la vulnerabilidad principal es esencialmente la misma: un campo de consulta SQL que se supone que está reservado para un tipo particular de datos, como un número, se pasa en su lugar información inesperada, como un comando. El comando, cuando se ejecuta, va más allá de los límites previstos, permitiendo un comportamiento potencialmente nefasto. Un campo de consulta se suele rellenar a partir de los datos introducidos en un formulario de una página web.
Veamos una simple comparación entre las sentencias SQL normales y las maliciosas:
Consulta SQL normal:
En esta consulta SQL normal, la cadena studentId se pasa a una sentencia SQL. El objetivo es buscar un alumno en la lista de estudiantes que coincida con el studentId introducido. Una vez encontrado, se devolverá el registro de ese estudiante. En pocas palabras, el comando dice "ve a buscar a este usuario y dame sus datos".
El código podría ser algo así:
studentId = getRequestString("studentId");
lookupStudent = "SELECT * FROM students WHERE studentId = " + studentId
Si un estudiante introduce una identificación de estudiante de 117 en un formulario de la página web etiquetado como "Por favor, introduce tu número de identificación de estudiante
la consulta SQL resultante tendrá el siguiente aspecto:
SELECT * FROM students WHERE studentId = 117;
Este comando devolverá el registro del estudiante concreto con un studentId, que es lo que el desarrollador que escribió la API espera que suceda.
Consulta de inyección de código SQL:
En este ejemplo, un atacante en vez de introducir un comando SQL o una lógica condicional en el campo de entrada, introduce un número de identificación de estudiante de:
Donde normalmente la consulta buscaría en la tabla de la base de datos la ID correspondiente, ahora busca una ID o comprueba si 1 es igual a 1. Como es de esperar, la sentencia es siempre verdadera para cada estudiante de la columna, y como resultado, la base de datos devolverá todos los datos de la tabla de estudiantes al atacante que realiza la consulta.
SELECT * FROM students WHERE studentId = 117 OR 1=1;
SQLi funciona al atacar a una interfaz de programación de aplicaciones o API vulnerable. En este caso, una API es la interfaz de software a través de la cual un servidor recibe y responde a las solicitudes.
Existen herramientas de uso común que permiten que un agente malicioso busque formularios automáticamente en un sitio web, y luego intente introducir varias consultas SQL, que pueden generar una respuesta que los desarrolladores del software del sitio web no pretendían con el fin de aprovechar una vulnerabilidad en la base de datos.
Las inyecciones de código SQL son fáciles de implementar y, curiosamente, también son bastante fáciles de prevenir si se aplican las prácticas de desarrollo adecuadas. La realidad es más turbia, ya que con plazos ajustados, desarrolladores inexpertos y código heredado suelen producirse prácticas de seguridad y una calidad de código variables. Un solo campo vulnerable en cualquier formulario o punto final de la API en un sitio web que tenga acceso a una base de datos puede ser suficiente para exponer una vulnerabilidad.
¿Cómo se evita un ataque de inyección de código SQL?
Hay varios métodos para reducir el riesgo de que se produzca una fuga de datos debido a una inyección de código SQL. Como práctica recomendada, se deben utilizar varias estrategias. Exploremos algunas de las implementaciones más comunes:
- Uso de sentencias preparadas (con consultas parametrizadas): este método de sanear las entradas de la base de datos implica obligar a los desarrolladores a definir primero todo el código SQL y, a continuación, a pasar solo parámetros específicos a la consulta SQL; los datos introducidos reciben explícitamente un alcance limitado que no pueden sobrepasar. Esto permite que la base de datos distinga entre los datos que se introducen y el código que se va a ejecutar, independientemente del tipo de datos introducidos en el campo de entrada. Algunas bibliotecas de asignación objeto-relacional (ORM) se suelen utilizar para este propósito, ya que algunas versiones sanean las entradas de la base de datos automáticamente.
- Eludir toda la entrada suministrada por el usuario: cuando se escribe SQL, algunos caracteres o palabras específicas tienen un significado particular. Por ejemplo, el carácter '*' significa "cualquiera" y la palabra "O" es un condicional. Para evitar que los usuarios introduzcan estos caracteres de forma accidental o malintencionada en una solicitud de la API a la base de datos, se puede eludir la entrada suministrada por el usuario. Eludir un carácter es la forma de decirle a la base de datos que no lo analice como un comando o condicional, sino que lo trate como una entrada literal.
- Uso de procedimientos almacenados: aunque no es una estrategia de seguridad robusta por sí misma, los procedimientos almacenados pueden ayudar a limitar el riesgo asociado a la inyección de código SQL. Al limitar adecuadamente los permisos de la cuenta de la base de datos que ejecuta las consultas SQL, incluso el código de aplicación no robusto que es vulnerable a la inyección SQL carecerá de los permisos necesarios para manipular tablas de la base de datos no relacionadas. Los procedimientos almacenados también pueden comprobar el tipo de los parámetros de entrada, impidiendo que se introduzcan datos que incumplan el tipo que el campo está diseñado para recibir. En los casos en que las consultas estáticas sean insuficientes, los procedimientos almacenados suelen evitarse.
- Aplicar el mínimo privilegio: como regla general, en todos los casos en los que un sitio web necesite utilizar SQL dinámico, es importante reducir la exposición a la inyección de código SQL limitando los permisos al ámbito más estrecho necesario para ejecutar la consulta pertinente. En su forma más obvia, esto significa que una cuenta administrativa no debería, en ningún caso, ejecutar comandos SQL como resultado de una llamada a la API de una solicitud no autorizada. Aunque los procedimientos almacenados se utilizan mejor para las consultas estáticas, la aplicación de los privilegios mínimos puede ayudar a reducir los riesgos de las consultas SQL dinámicas.
¿Qué es un ataque de inyección de código SQL compuesto?
Para evadir las medidas de seguridad, los atacantes más astutos a veces implementan ataques multivectoriales contra un sitio web objetivo. Aunque un solo ataque puede ser mitigado, también puede convertirse en el centro de atención de los administradores de bases de datos y de los equipos de seguridad de la información. Los ataques DDoS, el secuestro de DNS y otros métodos de interrupción se utilizan a veces como distracción para implementar ataques de inyección de código SQL de gran alcance. Por ello, una estrategia integral de mitigación de amenazas proporciona la más amplia protección. El firewall de aplicaciones web de Cloudflare, la mitigación de DDoS y la seguridad de DNS constan de elementos básicos de una estrategia de seguridad holística.
Preguntas frecuentes
¿Qué es la inyección de código SQL (SQLi)?
La inyección de código SQL es un tipo de ciberataque en el que los atacantes insertan comandos SQL maliciosos en los campos de entrada. Si se ejecutan los comandos, los atacantes pueden manipular o recuperar información de una base de datos sin autorización. En términos más sencillos, la inyección de código SQL se produce cuando los atacantes envían código ejecutable a lugares en los que una aplicación espera datos normales.
¿Cómo funciona un ataque de inyección de código SQL?
Los atacantes introducen un comando SQL en un campo de formulario. Después de que se envía el formulario, el backend de la aplicación recibe el comando y luego lo ejecuta realmente. Esto genera una respuesta o una acción que los desarrolladores de la aplicación no pretendían. Los atacantes pueden usar la inyección de código SQL para obtener información confidencial de una base de datos o alterar su contenido.
¿Qué puede suceder si un ataque de inyección de código SQL tiene éxito?
Una inyección de código SQL exitosa puede permitir a los atacantes suplantar identidades de usuarios, obtener privilegios de administrador, alterar o eliminar datos, recuperar todos los datos del servidor o incluso obtener acceso root a la máquina.
¿Cuáles son algunas estrategias eficaces para evitar la inyección de código SQL?
Las estrategias de prevención de inyecciones SQL incluyen el uso de sentencias preparadas, el escape de entradas de los usuarios, la implementación de procedimientos almacenados y la aplicación de un acceso con privilegios mínimos para garantizar que solo se concedan los permisos necesarios.
¿Qué son las sentencias preparadas y cómo ayudan a prevenir la inyección de código SQL?
Las sentencias preparadas separan el código SQL de las entradas del usuario mediante la precompilación del código SQL. Esto impide que los atacantes inyecten código malicioso, ya que la base de datos trata la entrada como datos y no como comandos ejecutables.
¿Por qué es importante escapar la entrada del usuario para evitar la inyección de código SQL?
Al escapar la entrada del usuario, se garantiza que los caracteres especiales se traten como texto sin formato en lugar de como parte de un comando SQL, lo que reduce el riesgo de que la entrada del usuario se interprete como instrucciones ejecutables.
¿Cómo pueden los procedimientos almacenados ayudar a reducir el riesgo de inyección de código SQL?
Los procedimientos almacenados pueden limitar los tipos y el alcance de las operaciones en la base de datos. Cuando se diseñan adecuadamente, limitan lo que el código inyectado puede hacer, aunque no constituyen una defensa completa por sí mismos.
¿Qué significa implementar el principio de privilegios mínimos en el contexto de la prevención de la inyección SQL?
Aplicar el principio de privilegio mínimo significa restringir los permisos de las cuentas de la base de datos únicamente a lo necesario. Esto minimiza el daño potencial si un atacante explota una vulnerabilidad de inyección de código SQL.