Všichni víme, že pokud je jakýkoli kód aplikace špatně napsaný, může kdokoli hacknout informace pomocí malého triku, jako je SQL Injection. V tomto příspěvku uvádím příklad, který demonstruje, jak může být SQL Injection zranitelné vůči aplikaci a jak tomu můžete zabránit.
Demonstrace je založena na tabulce EMP schématu SCOTT. Chcete-li stáhnout skript schématu SCOTT, klikněte na následující odkaz Stáhnout skript schématu Scott.
Příklad provedení SQL Injection
V této části uvádím příklad uložené procedury PL/SQL, která přijme parametr číslo zaměstnance jako (p_empno) pro zobrazení mzdy pro tohoto zaměstnance. V kódu používám zřetězení hodnoty tohoto parametru (p_empno) v řetězci příkazu SQL pro REF CURSOR, což se nedoporučuje a bude příčinou úspěšné SQL Injection. Níže je postup:
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; /
Nyní vyzkoušíme výše uvedený postup normálně předáním čísla zaměstnance.
Test
SET SERVEROUTPUT ON; BEGIN prc_get_emp_sal ('7566'); END; /
Výstup
JONES -- 27706.89 PL/SQL procedure successfully completed.
Do této chvíle je vše v pořádku. Protože jsme správně nazvali proceduru. Nyní uvidíme, jak můžeme hacknout výše uvedený postup pomocí triku SQL Injection k získání platu všech zaměstnanců. Možná to někdy chcete udělat i vy. Vtip!
Test pomocí SQL Injection
SET SERVEROUTPUT ON; BEGIN prc_get_emp_sal ('X'' OR ''1''= ''1'); END; /
Úspěšný výstup SQL Injection
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.
Páni, nyní můžete vidět plat každého zaměstnance pomocí tohoto triku SQL Injection. Jen si představte, že máte textové pole v aplikaci, ať už je to prohlížeč nebo desktop, a hodnotu předáváte přímo do procedury, a pokud použijete výše uvedený trik, pak se to jistě stane.
Příklad, jak zabránit vkládání SQL
Nyní upravíme výše uvedenou proceduru tak, aby místo zřetězení hodnoty parametru používala proměnnou vazby, takže žádný trik s SQL Injection nemůže fungovat.
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; /
Výše uvedený postup normálně vyzkoušejte
SET SERVEROUTPUT ON; BEGIN prc_get_emp_sal_2 ('7566'); END; /
Výstup
JONES -- 27706.89 PL/SQL procedure successfully completed.
Otestujte výše uvedený postup pomocí SQL Injection
SET SERVEROUTPUT ON; BEGIN prc_get_emp_sal_2 ('1'' OR ''1''= ''1'); END; /
Neúspěšný výstup SQL Injection
Can not fetch any records for: 1' OR '1'= '1 PL/SQL procedure successfully completed.
Poznamenejte si to, pokud vytváříte programy PL/SQL pomocí dynamického SQL, použijte metody vazby.