Las bases de datos siempre se encuentran expuestas a ser atacadas por personas mal intencionadas. Eso le puede ocurrir tanto a una Base de Datos que se encuentra en una red local como a una Base de Datos que se encuentra en una red remota, como Internet, por ejemplo. En este último caso el peligro es mucho mayor porque el atacante puede estar en la otra mitad del mundo y aunque lo descubramos no se podrá tomar medidas punitivas contra él. En cambio, si el atacante es un empleado de nuestra propia empresa siempre de alguna forma se le podrá castigar.

Nuestra tarea, por supuesto, es evitar que los ataques tengan éxito. Para ello debemos proteger a la Base de Datos lo más que podamos. A veces nuestros esfuerzos serán insuficientes pero en general los atacantes desistirán de continuar con sus ataques si se dan cuenta que se enfrentan a una Base de Datos que está muy protegida.

Una forma común de atacarla es a través de un método llamado en inglés “SQL injection”.

¿Qué significa “SQL injection”?

Que al comando SQL se le está agregando algo, se le está inyectando algo. Un código que no debería estar. Ese código adicional que agregó el atacante es el que nos causará problemas.

Ejemplo 1. Un ataque trivial de SQL injection

Supongamos que tenemos un sitio web para vender productos en línea. Los visitantes de nuestro sitio web pueden escribir el código del producto que les interesa conocer características y precios.

Todo bien hasta ahí, ¿verdad?

Quizás no, si no tomamos las debidas precauciones puede ser muy vulnerable.

En nuestra página web tenemos un campo de texto donde el visitante escribirá el código del producto que le interesa y un botón “submit” que usará para enviar su solicitud. En nuestro programa escribimos algo así:

lcComando = '''SELECT * FROM PRODUCTOS WHERE PRD_CODIGO = ' || lcCodigo || ';'''

Un vistitante normal podría querer conocer las características y precios del producto que tiene código 127 y entonces nuestro comando quedaría como:

lcComando = 'SELECT * FROM PRODUCTOS WHERE PRD_CODIGO = 127';

Y estaría perfecto, en condiciones normales no tendríamos problemas. Pero un visitante malintencionado podría escribir algo como:

127 or 1=1

 con lo cual, nuestro comando quedaría como:

lcComando = 'SELECT * FROM PRODUCTOS WHERE PRD_CODIGO = 127 or 1=1';

¡¡¡CUIDADO!!! esa condición SIEMPRE será verdadera porque SIEMPRE tendremos que 1 es igual a 1.

En este caso el atacante podrá ver las características y precios no solamente del producto cuyo código es 127 sino de TODOS los productos que tenemos en nuestra Base de Datos.

¿No importa que los vea, están para ser vistos?

Quizás en el caso de los productos no importe, pero en otros casos sí podría importar.

Ejemplo 2. Un ataque peligroso de SQL injection

El Ejemplo 1. mostró el concepto pero no era peligroso porque el atacante solamente vio datos, no modificó ni borró algo, entonces en muchos casos sería algo trivial y no muy preocupante. Pero el atacante sí puede borrar algo, si escribe:

127;DELETE FROM PRODUCTOS

porque en ese caso nuestro comando quedaría así:

lcComando = 'SELECT * FROM PRODUCTOS WHERE PRD_CODIGO = 127;DELETE FROM PRODUCTOS';

 ¿Y qué hará el Firebird en ese caso?

Pues ignorará al primer comando (o sea, el SELECT) y ejecutará el segundo comando (o sea el DELETE).

Y ahora, lo que hizo el atacante es MUY PELIGROSO porque borró todas las filas de nuestra tabla llamada PRODUCTOS.

Detectando si el ataque tuvo éxito

¿Y cómo puede saber el atacante si su ataque tuvo éxito?

Pues simplemente escribiendo el código de un producto que debía existir, por ejemplo el 127, con lo cual nuestro comando quedaría así:

lcComando = 'SELECT * FROM PRODUCTOS WHERE PRD_CODIGO = 127';

Si el atacante escribió 127 antes de lanzar el ataque y recibió datos, y luego de lanzar el ataque vuelve a escribir 127 y no recibe datos entonces puede estar 100% seguro de que su ataque tuvo éxito.

Claro, para eso tendría que saber que la tabla se llama PRODUCTOS, si la tabla tiene otro nombre evidentemente su ataque no funcionó. ¿Y qué puede hacer en ese caso? Pues probar con otros nombres similares, tales como: PROD, PRODS, PRODUCTO, PRODUCTS, ARTICULOS, ARTICLES, ARTICS, ARTS, etc.

Si alguna vez al enviar el código 127 no recibe datos entonces sabrá (al menos) cuatro cosas:

  1. El nombre de la tabla
  2. Que su ataque tuvo éxito
  3. Que el diseñador del sitio web no se preocupó por la seguridad
  4. Que puede continuar atacando a esa Base de Datos porque no está protegida

Ahora que ya borró todas las filas de la tabla PRODUCTOS puede continuar escribiendo otros comandos similares, tales como:

DELETE FROM CLIENTES
DELETE FROM PROVEEDORES
DELETE FROM USERS
DELETE FROM USUARIOS
DELETE FROM VENTAS
DROP CLIENTES
DROP PROVEEDORES
DROP VENTAS
etc.

En estos casos, no podrá saber si su ataque tuvo éxito o no, pero si escribe muchísimos comandos DELETE es muy probable que algunos de ellos sí borren todas las filas de algunas tablas.

¿Cómo evitamos los ataques de SQL injection?

Ya sabemos como la Base de Datos puede ser atacada, ¿cómo la defendemos?

  1. Validando que el visitante no introduzca espacios en blanco
  2. Validando que el visitante no introduzca puntos y comas
  3. Validando que el visitante solamente introduzca dígitos (0 .. 9)
  4. Validando que el visitante no introduzca la palabra DELETE
  5. Validando que el visitante no introduzca la palabra MODIFY
  6. Validando que el visitante no introduzca la palabra DROP
  7. Validando que la longitud de nuestra variable (llamada lcComando en estos ejemplos) no sea mayor que la predeterminada. Si nuestros códigos tienen un máximo de 4 dígitos entonces la longitud de lcComando nunca debería ser mayor que 47 (en nuestros ejemplos, claro).

Entonces, en nuestro stored procedure (o en el código fuente de nuestro lenguaje de programación) deberíamos escribir algo como:

IF (POSITION('DROP' IN lcComando) > 0) THEN BEGIN
-- ERROR, no se debe ejecutar el comando, la Base de Datos fue atacada.
END

Conclusión:

Todas las bases de datos pueden ser atacadas y como puedes ver es demasiado fácil hacerlo, ni siquiera se necesita de un programa que ayude. Aquí hemos visto algunos de los muchos métodos que pueden usar los atacantes. Mi objetivo no es enseñarte a atacar bases de datos sino mostrarte que son muy vulnerables y que si no las proteges entonces pueden ser facilmente destruidas.

Nunca debes confiar en que tu Base de Datos no será atacada porque no tiene algo interesante o de valor, muchos las atacan por diversión, porque lo toman como un juego, para pasar un buen rato, desafiando a sus amigos quienes realizan más ataques, cosas así. A muchos ni les interesa el contenido, solamente les resulta divertido hacerlo. Pero para tí puede ser un perjuicio enorme. Así que, mucho cuidado.

Artículo relacionado:

El índice del blog Firebird21

 

Anuncios