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.