Oracle
 sql >> Base de données >  >> RDS >> Oracle

Un exemple pour démontrer la vulnérabilité de l'injection SQL et sa prévention dans Oracle

Nous savons tous que si un code d'application est mal écrit, n'importe qui peut pirater les informations en utilisant une petite astuce telle que l'injection SQL. Dans cet article, je donne un exemple pour montrer comment l'injection SQL peut être vulnérable à une application et comment vous pouvez l'empêcher.

La démonstration est basée sur la table EMP du schéma SCOTT. Pour télécharger le script de schéma SCOTT, cliquez sur le lien suivant Télécharger le script de schéma Scott.

Un exemple pour effectuer une injection SQL

Dans cette section, je donne un exemple de procédure stockée PL/SQL qui acceptera un paramètre numéro d'employé comme (p_empno) pour afficher le salaire de cet employé. Dans le code, j'utilise la concaténation de cette valeur de paramètre (p_empno) dans la chaîne d'instruction SQL pour REF CURSOR, ce qui n'est pas recommandé et sera la cause d'une injection SQL réussie. Ci-dessous la procédure :

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;
/

Nous allons maintenant tester la procédure ci-dessus normalement en transmettant un numéro d'employé.

Tester

SET SERVEROUTPUT ON;

BEGIN
   prc_get_emp_sal ('7566');
END;
/

Sortie

JONES -- 27706.89
PL/SQL procedure successfully completed.

Jusqu'à maintenant tout va bien. Parce que nous avons correctement appelé la procédure. Nous allons maintenant voir comment nous pouvons pirater la procédure ci-dessus en utilisant l'astuce SQL Injection pour récupérer le salaire de tous les employés. Peut-être que parfois vous voulez aussi faire cela. Plaisanterie !

Tester avec l'injection SQL

SET SERVEROUTPUT ON;

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

Sortie d'injection SQL réussie

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, vous pouvez maintenant voir le salaire de chaque employé en utilisant cette astuce d'injection SQL. Imaginez simplement que vous ayez un champ de texte dans une application, qu'elle soit basée sur un navigateur ou sur un ordinateur de bureau et que vous transmettez la valeur directement à la procédure, et si vous utilisez l'astuce ci-dessus, cela se produira sûrement.

Un exemple pour empêcher l'injection SQL

Nous allons maintenant modifier la procédure ci-dessus pour utiliser la variable de liaison au lieu de concaténer la valeur du paramètre et de cette façon, aucune astuce d'injection SQL ne peut fonctionner.

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;
/

Testez la procédure ci-dessus normalement

SET SERVEROUTPUT ON;

BEGIN
   prc_get_emp_sal_2 ('7566');
END;
/

Sortie

JONES -- 27706.89
PL/SQL procedure successfully completed.

Testez la procédure ci-dessus à l'aide de l'injection SQL

SET SERVEROUTPUT ON;

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

Échec de la sortie d'injection SQL

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

Alors notez-le, si vous créez des programmes PL/SQL à l'aide de SQL dynamique, utilisez les méthodes de liaison.