sql >> Base de Datos >  >> RDS >> Oracle

Un ejemplo para demostrar la vulnerabilidad de la inyección SQL y su prevención en Oracle

Todos sabemos que si el código de una aplicación está mal escrito, cualquiera puede piratear la información usando un pequeño truco como la inyección SQL. En esta publicación, doy un ejemplo para demostrar cómo SQL Injection podría ser vulnerable a una aplicación y cómo puede evitarlo.

La demostración se basa en la tabla EMP del esquema SCOTT. Para descargar el script de esquema de SCOTT, haga clic en el siguiente enlace Descargar script de esquema de Scott.

Un ejemplo para realizar una inyección SQL

En esta sección, doy un ejemplo de un procedimiento almacenado PL/SQL que aceptará un número de empleado de parámetro como (p_empno) para mostrar el salario de ese empleado. En el código, estoy usando la concatenación del valor de ese parámetro (p_empno) en la cadena de instrucción SQL para REF CURSOR, que no se recomienda y será la causa de una inyección de SQL exitosa. A continuación se muestra el procedimiento:

CREATE OR REPLACE PROCEDURE PRC_GET_EMP_SAL (p_empno VARCHAR2)
IS
   --Declare a ref cursor and local variables--
   TYPE C IS REF CURSOR;

   CUR_EMP   C;
   L_ENAME   VARCHAR2 (100);
   L_SAL     NUMBER;
   L_STMT    VARCHAR2 (4000);
BEGIN
   --Open the ref cursor for a Dynamic SELECT statement--
   L_STMT := 'SELECT ename, sal 
            FROM emp 
            WHERE empno = ''' || p_empno || '''';

   OPEN CUR_EMP FOR L_STMT;

   LOOP
      --Fetch the result set and print the result set--
      FETCH CUR_EMP
      INTO L_ENAME, L_SAL;

      EXIT WHEN CUR_EMP%NOTFOUND;
      DBMS_OUTPUT.PUT_LINE (L_ENAME || ' -- ' || L_SAL);
   END LOOP;

   CLOSE CUR_EMP;
END;
/

Ahora vamos a probar el procedimiento anterior normalmente pasando un número de empleado.

Prueba

SET SERVEROUTPUT ON;

BEGIN
   prc_get_emp_sal ('7566');
END;
/

Salida

JONES -- 27706.89
PL/SQL procedure successfully completed.

Hasta ahora todo está bien. Porque llamamos correctamente al procedimiento. Ahora veremos cómo podemos piratear el procedimiento anterior utilizando el truco de inyección SQL para obtener el salario de todos los empleados. Quizás a veces tú también quieras hacer esto. ¡Bromeando!

Prueba usando inyección SQL

SET SERVEROUTPUT ON;

BEGIN
   prc_get_emp_sal ('X'' OR ''1''= ''1');
END;
/

Salida de inyección SQL exitosa

WARD -- 11641.56
JONES -- 27706.89
MARTIN -- 11641.56
BLAKE -- 26542.7
CLARK -- 22817.41
SCOTT -- 83819.06
KING -- 46566.18
TURNER -- 13969.85
ADAMS -- 10244.6
JAMES -- 8847.64
FORD -- 27939.74
MILLER -- 12107.2
PL/SQL procedure successfully completed.

Wow, ahora puedes ver el salario de cada empleado usando este truco de inyección SQL. Imagínese que tiene un campo de texto en una aplicación, ya sea basada en navegador o de escritorio, y está pasando el valor directamente al procedimiento, y si usa el truco anterior, seguramente esto sucederá.

Un ejemplo para prevenir la inyección SQL

Ahora modificaremos el procedimiento anterior para usar la variable de vinculación en lugar de concatenar el valor del parámetro y de esta manera no funcionará ningún truco de inyección SQL.

CREATE OR REPLACE PROCEDURE PRC_GET_EMP_SAL_2 (p_empno VARCHAR2)
IS
   --Declare a ref cursor and local variables--
   TYPE C IS REF CURSOR;

   CUR_EMP   C;
   L_ENAME   VARCHAR2 (100);
   L_SAL     NUMBER;
   L_STMT    VARCHAR2 (4000);
BEGIN
   --Open the ref cursor for a Dynamic SELECT statement--
   L_STMT := 'SELECT ename, sal 
            FROM emp 
            WHERE empno = :p_bind_empno';

   OPEN CUR_EMP FOR L_STMT USING p_EMPNO;

   LOOP
      --Fetch the result set and print the result set--
      FETCH CUR_EMP
      INTO L_ENAME, L_SAL;

      EXIT WHEN CUR_EMP%NOTFOUND;
      DBMS_OUTPUT.PUT_LINE (L_ENAME || ' -- ' || L_SAL);
   END LOOP;

   CLOSE CUR_EMP;
EXCEPTION
   WHEN OTHERS
   THEN
      DBMS_OUTPUT.PUT_LINE ('Can not fetch any records for: ' || p_empno);
END;
/

Pruebe el procedimiento anterior normalmente

SET SERVEROUTPUT ON;

BEGIN
   prc_get_emp_sal_2 ('7566');
END;
/

Salida

JONES -- 27706.89
PL/SQL procedure successfully completed.

Pruebe el procedimiento anterior usando SQL Injection

SET SERVEROUTPUT ON;

BEGIN
   prc_get_emp_sal_2 ('1'' OR ''1''= ''1');
END;
/

Salida de inyección SQL fallida

Can not fetch any records for: 1' OR '1'= '1
PL/SQL procedure successfully completed.

Así que anótelo, si está creando programas PL/SQL usando SQL dinámico, use los métodos de vinculación.