Coders Conquer Security: Compartir y aprender - Inyección SQL

Publicado el 06 de diciembre de 2018
por Jaap Karan Singh
ESTUDIO DE CASO

Coders Conquer Security: Compartir y aprender - Inyección SQL

Publicado el 06 de diciembre de 2018
por Jaap Karan Singh
Ver recurso
Ver recurso

En términos sencillos, SQL (o Structured Query Language) es el lenguaje utilizado para comunicarse con las bases de datos relacionales; es el lenguaje de consulta que utilizan los desarrolladores, los administradores de bases de datos y las aplicaciones para gestionar las enormes cantidades de datos que se generan cada día.

Nuestros datos se están convirtiendo rápidamente en una de las mercancías más valiosas del mundo... y cuando algo es valioso, los malos querrán poner sus manos en él para su beneficio.

Los atacantes están utilizando la inyección SQL, una de las vulnerabilidades de datos más antiguas(¡desde 1998!) y más molestas que existen, para robar y cambiar la información sensible disponible en millones de bases de datos de todo el mundo. Es insidiosa, y los desarrolladores deben entender la inyección SQL (así como la forma de defenderse contra ella) si queremos mantener nuestros datos a salvo.

Para ello, discutiremos tres aspectos clave de la inyección SQL:

  • Cómo funciona
  • Por qué es tan peligroso
  • Cómo defenderse

Comprender la Inyección SQL

La inyección SQL se puede entender con una palabra: contexto.

Dentro de una aplicación, existen dos contextos: uno para los datos y otro para el código. El contexto de código indica al ordenador qué debe ejecutar y lo separa de los datos que debe procesar.

La inyección SQL se produce cuando un atacante introduce datos que son tratados erróneamente como código por el intérprete de SQL.

Un ejemplo es un campo de entrada en un sitio web, donde un atacante introduce ''' OR 1=1" y se añade al final de una consulta SQL. Cuando esta consulta se ejecuta, devuelve "true" para cada fila de la base de datos. Esto significa que se devolverán todos los registros de la tabla consultada.

Las implicaciones de la inyección SQL pueden ser catastróficas. Si esto ocurre en una página de inicio de sesión, podría devolver todos los registros de los usuarios, incluyendo posiblemente los nombres de usuario y las contraseñas. Si una simple consulta para sacar datos tiene éxito, las consultas para cambiar los datos también lo harían.

Echemos un vistazo a un código vulnerable para que pueda ver cómo es una vulnerabilidad de inyección SQL en carne y hueso.

Mira este código:

String query = "SELECT account balance FROM user_data WHERE user_name = "
+ request.getParameter("customerName");
try {
   Statement statement = connection.createStatement( ... );
   ResultSet results = statement.executeQuery( query );
}

El código aquí simplemente añade la información de los parámetros del cliente al final de la consulta SQL sin ninguna validación. Cuando esto ocurre, un atacante puede introducir código en un campo de entrada o en los parámetros de la URL y se ejecutará.

La clave no es que los atacantes sólo puedan añadir ''' OR 1=1" a cada consulta SELECT, sino que un atacante puede manipular cualquier tipo de consulta SQL (INSERT, UPDATE, DELETE, DROP, etc.) y ampliarla con cualquier cosa que soporte la base de datos. Hay grandes recursos y herramientas disponibles en el dominio público que muestran lo que es posible.

Pronto aprenderemos a corregir este problema. En primer lugar, vamos a entender cuánto daño se puede hacer.

Por qué la inyección SQL es tan peligrosa

Estos son sólo tres ejemplos de infracciones causadas por la inyección SQL:

  • El sitio web de la Junta Electoral de Illinois fue violado debido a vulnerabilidades de inyección SQL. Los atacantes robaron los datos personales de 200.000 ciudadanos estadounidenses. Por la naturaleza de la vulnerabilidad encontrada, los atacantes podrían haber modificado también los datos, aunque no lo hicieron.
  • Hetzner, una empresa sudafricana de alojamiento de sitios web, sufrió un ataque que afectó a 40.000 registros de clientes. Una vulnerabilidad de inyección SQL condujo al posible robo de todos los registros de clientes de su base de datos.
  • Un proveedor de servicios financieros católicos en Minnesota, Estados Unidos, fue vulnerado mediante inyección SQL. Se robaron los datos de las cuentas, incluidos los números de cuenta, de casi 130.000 clientes.

Los datos sensibles pueden utilizarse para hacerse con cuentas, restablecer contraseñas, robar dinero o cometer fraudes.

Incluso la información que no se considera sensible o de identificación personal puede utilizarse para otros ataques. La información de la dirección o los últimos cuatro dígitos de su número de identificación gubernamental pueden ser utilizados para hacerse pasar por usted ante las empresas, o para restablecer su contraseña.

Cuando un ataque tiene éxito, los clientes pueden perder la confianza en la empresa. Recuperarse de los daños en los sistemas o de las multas reglamentarias puede costar millones de dólares.

Pero no tiene por qué acabar así para ti.

Derrotar la inyección SQL

La inyección SQL puede ser derrotada etiquetando claramente las partes de su aplicación, para que el ordenador sepa si una determinada parte son datos o código a ejecutar. Esto puede hacerse utilizando consultas parametrizadas.

Cuando las consultas SQL utilizan parámetros, el intérprete SQL utilizará el parámetro sólo como datos. No lo ejecuta como código.

Por ejemplo, un ataque como ''' OR 1=1" no funcionará. La base de datos buscará la cadena "OR 1=1" y no la encontrará en la base de datos. Simplemente se encogerá de hombros y dirá: "Lo siento, no puedo encontrarlo".

Un ejemplo de consulta parametrizada en Java tiene el siguiente aspecto:

La mayoría de los marcos de desarrollo proporcionan defensas integradas contra la inyección SQL.

Los mapeadores relacionales de objetos (ORM), como Entity Framework en la familia .NET, parametrizan las consultas por defecto. Esto se encargará de la inyección SQL sin ningún esfuerzo por su parte.

Sin embargo, debe saber cómo funciona su ORM específico. Por ejemplo, Hibernate, un ORM muy popular en el mundo de Java, puede ser vulnerable a la inyección SQL si se utiliza de forma incorrecta.

Parametrizar las consultas es la primera y mejor defensa, pero hay otras. Los procedimientos almacenados también admiten parámetros SQL y pueden utilizarse para evitar la inyección SQL. Tenga en cuenta que los procedimientos almacenados también deben ser construidos correctamente para que esto funcione.

// This should REALLY be validated too
String custname = request.getParameter("customerName");
// perform input validation to detect attacks
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";

PreparedStatement pstmt = connection.preparedStatement( query );
pstmt.setString(1, custname);
ResultSet results = pstmt.executeQuery( );

Valide y sanee siempre sus entradas. Dado que algunos caracteres, como "OR 1=1", no van a ser introducidos por un usuario legítimo de tu aplicación, no hay necesidad de permitirlos. Puedes mostrar un mensaje de error al usuario o eliminarlos de tu entrada antes de procesarla.

Al decir esto, no dependas sólo de la validación y la higienización para protegerte. Los humanos inteligentes han encontrado formas de evitarlo. Son buenas estrategias de Defensa en Profundidad (DiD), pero la parametrización es la forma segura de cubrir todas las bases.

Otra buena estrategia de DiD es utilizar el "mínimo privilegio" dentro de la base de datos y la lista blanca de entrada. Aplicar el privilegio mínimo significa que su aplicación no tiene un poder ilimitado dentro de la base de datos. Si un atacante consigue acceder, el daño que puede hacer es limitado.

OWASP tiene una gran hoja de trucos de inyección SQL disponible para mostrar cómo manejar esta vulnerabilidad en varios lenguajes y plataformas... pero si quieres ir más allá, puedes jugar un desafío de inyección SQL en tu lenguaje preferido en nuestra plataforma ahora mismo; aquí hay algunos de los más populares para empezar:

Inyección SQL en C#

Inyección SQL en Node.js

Inyección SQL en Python Django

Inyección SQL en Java Spring

Comienza el viaje

Has hecho un gran progreso en la comprensión de la inyección SQL, y los pasos necesarios para solucionarlo. ¡Impresionante!

Ya hemos hablado de cómo se produce la inyección SQL; por lo general, un atacante utiliza la entrada para controlar las consultas de su base de datos para sus propios fines nefastos.

También hemos visto los daños causados por la explotación de las vulnerabilidades de inyección SQL: Las cuentas pueden verse comprometidas y se pierden millones de dólares... una pesadilla, y muy cara.

Hemos visto cómo prevenir la inyección SQL:

  • Parametrización de las consultas
  • Uso de mapeadores relacionales de objetos y procedimientos almacenados
  • Validación y lista blanca de entradas de usuarios

Ahora, depende de ti. La práctica es la mejor manera de seguir aprendiendo y dominando el idioma, así que ¿por qué no echas un vistazo a nuestros Recursos de aprendizaje sobre la inyección de SQL, y luego pruebe nuestra demostración gratuita de la plataforma? Estarás en camino de convertirte en un Secure Code Warrior.

Ver recurso
Ver recurso

Autor

Jaap Karan Singh

¿Quieres más?

Sumérjase en nuestras últimas ideas sobre codificación segura en el blog.

Nuestra amplia biblioteca de recursos tiene como objetivo potenciar el enfoque humano de la mejora de la codificación segura.

Ver blog
¿Quieres más?

Obtenga las últimas investigaciones sobre la seguridad impulsada por los desarrolladores

Nuestra amplia biblioteca de recursos está repleta de recursos útiles, desde libros blancos hasta seminarios web, que le ayudarán a iniciarse en la codificación segura orientada a los desarrolladores. Explórela ahora.

Centro de recursos

Coders Conquer Security: Compartir y aprender - Inyección SQL

Publicado el 06 de diciembre de 2018
Por Jaap Karan Singh

En términos sencillos, SQL (o Structured Query Language) es el lenguaje utilizado para comunicarse con las bases de datos relacionales; es el lenguaje de consulta que utilizan los desarrolladores, los administradores de bases de datos y las aplicaciones para gestionar las enormes cantidades de datos que se generan cada día.

Nuestros datos se están convirtiendo rápidamente en una de las mercancías más valiosas del mundo... y cuando algo es valioso, los malos querrán poner sus manos en él para su beneficio.

Los atacantes están utilizando la inyección SQL, una de las vulnerabilidades de datos más antiguas(¡desde 1998!) y más molestas que existen, para robar y cambiar la información sensible disponible en millones de bases de datos de todo el mundo. Es insidiosa, y los desarrolladores deben entender la inyección SQL (así como la forma de defenderse contra ella) si queremos mantener nuestros datos a salvo.

Para ello, discutiremos tres aspectos clave de la inyección SQL:

  • Cómo funciona
  • Por qué es tan peligroso
  • Cómo defenderse

Comprender la Inyección SQL

La inyección SQL se puede entender con una palabra: contexto.

Dentro de una aplicación, existen dos contextos: uno para los datos y otro para el código. El contexto de código indica al ordenador qué debe ejecutar y lo separa de los datos que debe procesar.

La inyección SQL se produce cuando un atacante introduce datos que son tratados erróneamente como código por el intérprete de SQL.

Un ejemplo es un campo de entrada en un sitio web, donde un atacante introduce ''' OR 1=1" y se añade al final de una consulta SQL. Cuando esta consulta se ejecuta, devuelve "true" para cada fila de la base de datos. Esto significa que se devolverán todos los registros de la tabla consultada.

Las implicaciones de la inyección SQL pueden ser catastróficas. Si esto ocurre en una página de inicio de sesión, podría devolver todos los registros de los usuarios, incluyendo posiblemente los nombres de usuario y las contraseñas. Si una simple consulta para sacar datos tiene éxito, las consultas para cambiar los datos también lo harían.

Echemos un vistazo a un código vulnerable para que pueda ver cómo es una vulnerabilidad de inyección SQL en carne y hueso.

Mira este código:

String query = "SELECT account balance FROM user_data WHERE user_name = "
+ request.getParameter("customerName");
try {
   Statement statement = connection.createStatement( ... );
   ResultSet results = statement.executeQuery( query );
}

El código aquí simplemente añade la información de los parámetros del cliente al final de la consulta SQL sin ninguna validación. Cuando esto ocurre, un atacante puede introducir código en un campo de entrada o en los parámetros de la URL y se ejecutará.

La clave no es que los atacantes sólo puedan añadir ''' OR 1=1" a cada consulta SELECT, sino que un atacante puede manipular cualquier tipo de consulta SQL (INSERT, UPDATE, DELETE, DROP, etc.) y ampliarla con cualquier cosa que soporte la base de datos. Hay grandes recursos y herramientas disponibles en el dominio público que muestran lo que es posible.

Pronto aprenderemos a corregir este problema. En primer lugar, vamos a entender cuánto daño se puede hacer.

Por qué la inyección SQL es tan peligrosa

Estos son sólo tres ejemplos de infracciones causadas por la inyección SQL:

  • El sitio web de la Junta Electoral de Illinois fue violado debido a vulnerabilidades de inyección SQL. Los atacantes robaron los datos personales de 200.000 ciudadanos estadounidenses. Por la naturaleza de la vulnerabilidad encontrada, los atacantes podrían haber modificado también los datos, aunque no lo hicieron.
  • Hetzner, una empresa sudafricana de alojamiento de sitios web, sufrió un ataque que afectó a 40.000 registros de clientes. Una vulnerabilidad de inyección SQL condujo al posible robo de todos los registros de clientes de su base de datos.
  • Un proveedor de servicios financieros católicos en Minnesota, Estados Unidos, fue vulnerado mediante inyección SQL. Se robaron los datos de las cuentas, incluidos los números de cuenta, de casi 130.000 clientes.

Los datos sensibles pueden utilizarse para hacerse con cuentas, restablecer contraseñas, robar dinero o cometer fraudes.

Incluso la información que no se considera sensible o de identificación personal puede utilizarse para otros ataques. La información de la dirección o los últimos cuatro dígitos de su número de identificación gubernamental pueden ser utilizados para hacerse pasar por usted ante las empresas, o para restablecer su contraseña.

Cuando un ataque tiene éxito, los clientes pueden perder la confianza en la empresa. Recuperarse de los daños en los sistemas o de las multas reglamentarias puede costar millones de dólares.

Pero no tiene por qué acabar así para ti.

Derrotar la inyección SQL

La inyección SQL puede ser derrotada etiquetando claramente las partes de su aplicación, para que el ordenador sepa si una determinada parte son datos o código a ejecutar. Esto puede hacerse utilizando consultas parametrizadas.

Cuando las consultas SQL utilizan parámetros, el intérprete SQL utilizará el parámetro sólo como datos. No lo ejecuta como código.

Por ejemplo, un ataque como ''' OR 1=1" no funcionará. La base de datos buscará la cadena "OR 1=1" y no la encontrará en la base de datos. Simplemente se encogerá de hombros y dirá: "Lo siento, no puedo encontrarlo".

Un ejemplo de consulta parametrizada en Java tiene el siguiente aspecto:

La mayoría de los marcos de desarrollo proporcionan defensas integradas contra la inyección SQL.

Los mapeadores relacionales de objetos (ORM), como Entity Framework en la familia .NET, parametrizan las consultas por defecto. Esto se encargará de la inyección SQL sin ningún esfuerzo por su parte.

Sin embargo, debe saber cómo funciona su ORM específico. Por ejemplo, Hibernate, un ORM muy popular en el mundo de Java, puede ser vulnerable a la inyección SQL si se utiliza de forma incorrecta.

Parametrizar las consultas es la primera y mejor defensa, pero hay otras. Los procedimientos almacenados también admiten parámetros SQL y pueden utilizarse para evitar la inyección SQL. Tenga en cuenta que los procedimientos almacenados también deben ser construidos correctamente para que esto funcione.

// This should REALLY be validated too
String custname = request.getParameter("customerName");
// perform input validation to detect attacks
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";

PreparedStatement pstmt = connection.preparedStatement( query );
pstmt.setString(1, custname);
ResultSet results = pstmt.executeQuery( );

Valide y sanee siempre sus entradas. Dado que algunos caracteres, como "OR 1=1", no van a ser introducidos por un usuario legítimo de tu aplicación, no hay necesidad de permitirlos. Puedes mostrar un mensaje de error al usuario o eliminarlos de tu entrada antes de procesarla.

Al decir esto, no dependas sólo de la validación y la higienización para protegerte. Los humanos inteligentes han encontrado formas de evitarlo. Son buenas estrategias de Defensa en Profundidad (DiD), pero la parametrización es la forma segura de cubrir todas las bases.

Otra buena estrategia de DiD es utilizar el "mínimo privilegio" dentro de la base de datos y la lista blanca de entrada. Aplicar el privilegio mínimo significa que su aplicación no tiene un poder ilimitado dentro de la base de datos. Si un atacante consigue acceder, el daño que puede hacer es limitado.

OWASP tiene una gran hoja de trucos de inyección SQL disponible para mostrar cómo manejar esta vulnerabilidad en varios lenguajes y plataformas... pero si quieres ir más allá, puedes jugar un desafío de inyección SQL en tu lenguaje preferido en nuestra plataforma ahora mismo; aquí hay algunos de los más populares para empezar:

Inyección SQL en C#

Inyección SQL en Node.js

Inyección SQL en Python Django

Inyección SQL en Java Spring

Comienza el viaje

Has hecho un gran progreso en la comprensión de la inyección SQL, y los pasos necesarios para solucionarlo. ¡Impresionante!

Ya hemos hablado de cómo se produce la inyección SQL; por lo general, un atacante utiliza la entrada para controlar las consultas de su base de datos para sus propios fines nefastos.

También hemos visto los daños causados por la explotación de las vulnerabilidades de inyección SQL: Las cuentas pueden verse comprometidas y se pierden millones de dólares... una pesadilla, y muy cara.

Hemos visto cómo prevenir la inyección SQL:

  • Parametrización de las consultas
  • Uso de mapeadores relacionales de objetos y procedimientos almacenados
  • Validación y lista blanca de entradas de usuarios

Ahora, depende de ti. La práctica es la mejor manera de seguir aprendiendo y dominando el idioma, así que ¿por qué no echas un vistazo a nuestros Recursos de aprendizaje sobre la inyección de SQL, y luego pruebe nuestra demostración gratuita de la plataforma? Estarás en camino de convertirte en un Secure Code Warrior.

Nos gustaría contar con su permiso para enviarle información sobre nuestros productos y/o temas relacionados con la codificación segura. Siempre trataremos sus datos personales con el máximo cuidado y nunca los venderemos a otras empresas con fines de marketing.

Enviar
Para enviar el formulario, habilite las cookies "Analytics". Siéntase libre de desactivarlas de nuevo una vez que haya terminado.