elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: (TUTORIAL) Aprende a emular Sentinel Dongle By Yapis


+  Foro de elhacker.net
|-+  Programación
| |-+  Desarrollo Web
| | |-+  Bases de Datos (Moderador: Carloswaldo)
| | | |-+  Defenderse contra inyecciones SQL
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: Defenderse contra inyecciones SQL  (Leído 2,264 veces)
D3s0rd3n

Desconectado Desconectado

Mensajes: 97


Tu Mente es mi arma. Entregame tu mente


Ver Perfil
Defenderse contra inyecciones SQL
« en: 28 Noviembre 2023, 22:17 pm »

El Problema

La vulnerabilidad de una inyeccion SQL surge cuando el programador declara queries dinamicas en la logica de su base de Datos. Aqui hay un ejemplo en PHP de esta vulnerabilidad:

Código
  1. $offset = $_GET['offset'];
  2. $query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";
  3. $result = pg_query($conn, $query);
  4.  


 Estas queries son creadas por la concatenacion de strings que el usuario define. Para evitar esta vulnerabilidad El programador tiene dos opciones:

  • Dejar de usar queries dinamicas.
  • Evitar que el SQL malicioso del usuario afecte la logica de la base de Datos.

Aqui pretendo tratar unas medidas simples que los programadores pueden tomar para evitar o en todo caso reducir el daño de una iSQL. Las tecnicas incluidas aqui son casos generales, y tambien pueden ser aplicadas para defenderse de toros tipos de ataques similares como las inyecciones XPath y XQuery por ejemplo.

La ley del privilegio

Por lo general en la seguridad informatica es Buena idea que las aplicaciones se ejecuten con privilegios bajos, solo con lo necesario. Esto es especialmente verdad cuando se trata de una aplicacion que sera usado remotamente por usuarios en los que no se confia (por lo general es mala idea confiar en el usuario de tu aplicacion). Por eso quiero empezar con este tema, sirve como una Buena practica y mitiga El daño incluso despues de una explotacion exitosa.

La mejor manera para ejecutar esto es tener distintos usuarios de privilegio limitado en tu entorno. El error comun aqui es que muchos programadores toman El Camino facil de darle DBA o admin de base de Datos a las cuentas de su aplicacion. Esto es peligroso y aumenta el daño de una iSQL existosa. Esta bien que todo "funciona Bien" cuando lo haces pero si una aplicacion es comprometida el resto de la base de Datos queda expuesta.

La implementacion de esta medida varia segun la plataforma que estas usando pero la idea es la misma. Empieza de abajo hacia arriba,  no es recomendable darle todos los privilegios a un usuario de base de Datos e irle quitando los que no necesita. Puedes pasar por alto un privilegio sin darte cuenta pero el 1337 hacker que quiere tus Datos si lo identificara. Es por ESO que debes tomar en cuenta que es lo que necesita tu cuenta y darle solo eso. Una cuenta que solo lee Datos de una tabla solo require privilegios de lectura y solo para la tabla en cuestion. Por ejemplo, en una e-commerce una cuenta que solo arroja productos con su descripcion solo deberias de tener permisos de lectura solo para la tabla de productos y nada mas. El darle otros privilegios Seria una amenaza de seguridad. Si una cuenta solo require partes de una tabla, crea una view que se los da. Y a esta cuenta dale permiso solo para esa view y no para la tabla que hay detras.

Usando queries preparadas

Esta es la forma en que se deberia de enseñar a los programadores a hacer sus queries. En vez de usar un string para la queries, Este las toma en la forma de un parametro. Esto es Algo similar a como algunos lenguajes como perl manejan su funciona de system() precisamente para evitar una inyeccion. Este estilo le permite a tu base de Datos distinguir entre Datos y codigo. Ademas de que es mas facil de leer y te obliga a primero programar tu base de datos y despues pasar los parametros a la formacion de queries. Por ejemplo, si un hacker intenta buscar "juan' or '1'='1" en vez de ser vulnerable a que se ejecuten como codigo, la base de Datos buscara un usuario que se llame "juan' '1'='1".  Aqui una's maneras de hacerlo segun El lenguaje que uses:

  • JAVA EE: se usa PreparedStatement() con variables enlazadas
  • .NET: Usando queries parameterizadas como SqlCommand() o OleDbCommand().
  • PHP: Usa PDO con queries estrocamente declaradas con bindParam().
[lil]Hibernate: Usa parametros nombrados con createQuery().[/li]
[li]SQLite: Usa sqlite3_prepare() para crear un objeto de query.[/li]
[/list]

JAVA:

Código
  1. // Esto tambien deberia ser validado
  2. String nombreCliente = request.getParameter("nombre");
  3. String query = "SELECT saldo_cuenta FROM datos_usuarii WHERE nombre_cliente = ? ";
  4. PreparedStatement pstmt = connection.prepareStatement( query );
  5. pstmt.setString( 1, nombreCliente);
  6. ResultSet resultados = pstmt.executeQuery( );
  7.  

C# .NET:
 En .net la creacion y ejecucion de una query no cambian, solo pasa los parametros Al query usando Parameters.Add().

Código
  1. String query = "SELECT saldo_cuenta FROM datos_usuario WHERE nombre_usuario = ?";
  2. try {
  3.  OleDbCommand command = new OleDbCommand(query, connection);
  4.  command.Parameters.Add(new OleDbParameter("nombreCliente", CustomerName Name.Text));
  5.  OleDbDataReader reader = command.ExecuteReader();
  6.  // …
  7. } catch (OleDbException se) {
  8.  // En Caso de error
  9. }
  10.  

Practicamente cualquier lenguaje de programacion tiene manera de hacer esto (para mas ejemplos buscar OWASP parameterized query cheat sheet). Incluso las abstracciones de SQL tambien tienen esta capacidad como por ejemplo HQL antes mencionado:

Código
  1. //HQL no seguro usando concatenacion de strings
  2. Query HQLNoSeguro = SESSION.createQuery("from inventario where productoID='"+parametroUsuario+"'");
  3. //La misma pero en su forma Segura usando parametros nombrados
  4. Query HQLSeguro = SESSION.createQuery("from Inventorio where productoID=:productoid");
  5. HQLSeguro.setParameter("productoid", parametroUsuario);
  6.  

Una de Las ventajas de usar queries preparadas es que la logica se queda dentro de la aplicacion haciendola independiente de la base de datos.



En línea

Gobiernos del Mundo Industrial, ustedes, cansados gigantes de carne y acero
vengo del Ciberespacio, el nuevo hogar de la Mente. En nombre del futuro, les
pido en el pasado  que nos dejen en paz.  No son  bienvenidos entre nosotros.
No tienen ninguna soberania sobre el lugar donde nos reunimos.
D3s0rd3n

Desconectado Desconectado

Mensajes: 97


Tu Mente es mi arma. Entregame tu mente


Ver Perfil
Re: Defenderse contra inyecciones SQL
« Respuesta #1 en: 28 Noviembre 2023, 23:03 pm »

Procedimientos almacenados

Los procedimientos almacenados como tal no son exentos de una inyeccion SQL. Se requiere que sean implementados de la manera adecuada para que puedan incrementar la seguridad de tu base de datos y para esto los lenguajes de procedimientos almacenados tienen sus estandares.

Para que un procedimiento almacenado sea seguro, es necesario que el desarrollador construya declaraciones SQL con parametros que son parameterizados automaticamente. La diferencia entre una declaracion almacenada y un procedimiento almacenado es que El Codigo SQL de los procedimientos son guardados dentro de la misma base de datos y luego llamados por la aplicacion. Ambos son igual de effectivos para prevenir inyecciones SQL asi que tu puedes elegir el que mas se te acomoda.

Los procedimientos almacenados requieren permisos de ejecucion los cuales no estan disponibles por default. Esto es El aspecto de los procedimientos almacenados que aumenta El riesgo de impacto de una intrusion exitosa. Siendo que por lo general los sistemas DBA solo tienen 3 roles: de lectura, escritura y dueño. Tomando en cuenta la ley del privilegio esto nos pone en mayor riesgo siendo que se le tendra que asignar los privilegios de dueño a la base de datos para que los procedimientos funcionen.

Ejemplo implementacion Segura en JAVA

Aqui se usa la implementacion en Java de procedimientos almacenados de manera segura usando la interfaz CallableStatement para ejecutar una query de base de datos. El procedimiento pa_saldoCuenta (procedimiento que obtiene el saldo de una cuenta) tiene que ser definido primero en la base de datos.

Código
  1. // Esto deberia ser validado
  2. String nombreCliente = request.getParameter("nombre");
  3. try {
  4.  CallableStatement cs = connection.prepareCall("{call pa_saldoCuenta(?)}");
  5.  cs.setString(1, nombreCliente);
  6.  ResultSet resultado = cs.executeQuery();
  7.    …
  8. } catch (SQLException se) {
  9.  // En Caso de error
  10. }
  11.  


Ejemplo implementacion Segura en VB.NET

En Este ejemplo hacemos lo mismo que en El pasado usando la interfaz SqlCommand.

Código
  1. Try
  2.   Dim cmd As SqlCommand = new SqlCommand("pa_saldoCuenta", connection)
  3.   cmd.CommandType = CommandType.StoredProcedure
  4.   cmd.Parameters.Add(new SqlParameter("@nombreCliente", nombreCliente.Text))
  5.   Dim lector As SqlDataReader = cmd.ExecuteReader()
  6.   '...
  7. Catch es As errorSQL
  8.   'en Caso de error
  9. End Try
  10.  


En línea

Gobiernos del Mundo Industrial, ustedes, cansados gigantes de carne y acero
vengo del Ciberespacio, el nuevo hogar de la Mente. En nombre del futuro, les
pido en el pasado  que nos dejen en paz.  No son  bienvenidos entre nosotros.
No tienen ninguna soberania sobre el lugar donde nos reunimos.
D3s0rd3n

Desconectado Desconectado

Mensajes: 97


Tu Mente es mi arma. Entregame tu mente


Ver Perfil
Re: Defenderse contra inyecciones SQL
« Respuesta #2 en: 28 Noviembre 2023, 23:07 pm »

Validación de entrada

Si se enfrenta a partes de queries SQL que no pueden utilizar variables enlazadas, como los nombres de tablas o columnas, así como el indicador de orden de clasificación (ASC o DESC), la validación de entrada o el rediseño de la consulta es la defensa más adecuada. Cuando se necesitan nombres de tablas o columnas, lo ideal es que esos valores provengan del código y no de los parámetros del usuario.

 Si se utilizas valores de parámetros de usuario para referenviar diferentes nombres de tablas y nombres de columnas, esto es un síntoma de un diseño deficiente y se debe considerar una reescritura completa. Si eso no es posible, los desarrolladores deben asignar los valores de los parámetros a los nombres de columna o tabla legales o esperados para asegurarse de que la entrada del usuario no validada no termine en la consulta.

En el siguiente ejemplo, dado que nombreTabla se identifica como uno de los valores esperados para un nombre de tabla en esta query, se puede agregar directamente a la query SQL. Ten en cuenta que las funciones genéricas de validación de tablas pueden provocar la pérdida de datos, ya que los nombres de las tablas se utilizan en consultas donde no seon esperadas.

Código
  1. String nombreTabla;
  2. switch(PARAM):
  3.  CASE "Valor1": nombreTabla = "Tabla1";
  4.                 break;
  5.  CASE "Valor2": nombreTabla = "Tabla2";
  6.                 break;
  7.  ...
  8.  DEFAULT : throw NEW InputValidationException("Valor inesperado");
  9.  

Uso seguro de queries dinamicas

El uso de queries dinamicas dentro de los procedimientos almacenados es raro y deberia de ser evitado si es possible. Si se necesitan, se puede implementar una version Segura de ellas pero repito que su uso no es recomendado. Se deben de considerar regulas de validacion de entrada como anteriormente se menciono y el escapado de caracteres especiales para que no termine El SQL dinamico del procedimiento almacenado con alguna inyeccion. Especialmente cuando se trata de El uso de funciones como exec dentro del procedimiento almacenado.

Aqui un ejemplo de esto con El uso del orden de acomodo:

Código
  1. public String algunMetodo(boolean orden) {
  2. String querySQL = "alguna query x... order by valor1 " + (orden ? "ASC" : "DESC");`
  3. ...
  4.  

Esto asegura que si cambia el tipo de datos que el usuario ingresa (fecha, int, string, etc) Este cambio suceda de forma segura.

En fin la validacion de entrada es recomendable en todo caso incluso cuando se usan variables enlazadas.
En línea

Gobiernos del Mundo Industrial, ustedes, cansados gigantes de carne y acero
vengo del Ciberespacio, el nuevo hogar de la Mente. En nombre del futuro, les
pido en el pasado  que nos dejen en paz.  No son  bienvenidos entre nosotros.
No tienen ninguna soberania sobre el lugar donde nos reunimos.
Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
DLL contra inyecciones
Programación Visual Basic
XP. 0 1,402 Último mensaje 2 Octubre 2006, 03:58 am
por XP.
Proteger Mi Aplicación Contra Inyecciones
Programación Visual Basic
Martinss 1 1,602 Último mensaje 18 Octubre 2006, 21:57 pm
por Kizar
Defenderse de MITM o Sniffer
Hacking Wireless
Dettre 4 5,225 Último mensaje 12 Septiembre 2016, 20:40 pm
por Kaxperday
Recomendaciones para defenderse de los ataques ‘día cero’
Noticias
wolfbcn 0 1,772 Último mensaje 3 Febrero 2017, 02:00 am
por wolfbcn
Defenderse de ataques dentro de la propia red
Wireless en Windows
Descartes 8 4,722 Último mensaje 22 Mayo 2017, 13:35 pm
por warcry.
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines