Всички знаем, че ако кодът на приложението е лошо написан, тогава всеки може да хакне информацията, като използва малък трик като SQL инжекция. В тази публикация давам пример, за да демонстрирам как SQL инжекцията може да бъде уязвима към приложение и как можете да го предотвратите.
Демонстрацията се основава на таблицата EMP на схемата SCOTT. За да изтеглите скрипта на схемата на SCOTT, щракнете върху следната връзка Изтеглете скрипт за схема на Scott.
Пример за извършване на SQL инжекция
В този раздел давам пример за съхранена процедура в PL/SQL, която ще приеме параметър номер на служител като (p_empno), за да покаже заплатата за този служител. В кода използвам конкатенацията на стойността на този параметър (p_empno) в низа на SQL оператор за REF CURSOR, което не се препоръчва и ще бъде причина за успешно SQL инжектиране. По-долу е процедурата:
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; /
Сега щетестваме нормално горната процедура чрез предаване на номер на служител.
Тест
SET SERVEROUTPUT ON; BEGIN prc_get_emp_sal ('7566'); END; /
Изход
JONES -- 27706.89 PL/SQL procedure successfully completed.
До сега всичко е наред. Защото правилно нарекохме процедурата. Сега ще видим как можем да хакнем горната процедура, като използваме трика за SQL инжекция, за да получим заплатата на всички служители. Може би понякога и вие искате да направите това. Шегувам се!
Тест с помощта на SQL инжекция
SET SERVEROUTPUT ON; BEGIN prc_get_emp_sal ('X'' OR ''1''= ''1'); END; /
Успешен изход за инжектиране на SQL
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.
Уау, сега можете да видите заплатата на всеки служител, като използвате този трик за SQL инжекция. Само си представете, че имате текстово поле в приложение, независимо дали е базирано на браузър или десктоп, и предавате стойността веднага на процедурата и ако използвате горния трик, това със сигурност ще се случи.
Пример за предотвратяване на SQL инжекция
Сега ще модифицираме горната процедура, за да използваме променлива за свързване, вместо да свързваме стойността на параметъра и по този начин никакъв трик за 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; /
Изпробвайте горната процедура нормално
SET SERVEROUTPUT ON; BEGIN prc_get_emp_sal_2 ('7566'); END; /
Изход
JONES -- 27706.89 PL/SQL procedure successfully completed.
Тествайте горната процедура с SQL инжекция
SET SERVEROUTPUT ON; BEGIN prc_get_emp_sal_2 ('1'' OR ''1''= ''1'); END; /
Неуспешен изход за SQL инжекция
Can not fetch any records for: 1' OR '1'= '1 PL/SQL procedure successfully completed.
Така че забележете го, ако създавате PL/SQL програми с помощта на динамичен SQL, използвайте методите за свързване.