We weten allemaal dat als een applicatiecode slecht is geschreven, iedereen de informatie kan hacken door een klein trucje te gebruiken, zoals SQL-injectie. In dit bericht geef ik een voorbeeld om aan te tonen hoe SQL-injectie kwetsbaar kan zijn voor een toepassing en hoe u dit kunt voorkomen.
De demonstratie is gebaseerd op de EMP-tabel van het SCOTT-schema. Om het SCOTT-schemascript te downloaden, klikt u op de volgende link Scott Schema Script downloaden.
Een voorbeeld om SQL-injectie uit te voeren
In deze sectie geef ik een voorbeeld van een PL/SQL-opgeslagen procedure die een parameter werknemernummer accepteert als (p_empno) om het salaris voor die werknemer weer te geven. In de code gebruik ik de aaneenschakeling van die parameterwaarde (p_empno) in de SQL-instructiereeks voor REF CURSOR, wat niet wordt aanbevolen en de oorzaak zal zijn van succesvolle SQL-injectie. Hieronder vindt u de procedure:
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; /
Nu zullen we de bovenstaande procedure normaal testen door een personeelsnummer door te geven.
Test
SET SERVEROUTPUT ON; BEGIN prc_get_emp_sal ('7566'); END; /
Uitvoer
JONES -- 27706.89 PL/SQL procedure successfully completed.
Tot nu toe is alles in orde. Omdat we de procedure correct hebben genoemd. Nu zullen we zien hoe we de bovenstaande procedure kunnen hacken door de SQL-injectietruc te gebruiken om het salaris van alle werknemers op te halen. Misschien wil jij dit ook wel eens doen. Een grapje!
Test met SQL-injectie
SET SERVEROUTPUT ON; BEGIN prc_get_emp_sal ('X'' OR ''1''= ''1'); END; /
Succesvolle uitvoer van SQL-injectie
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.
Wauw, nu kun je het salaris van elke werknemer zien met deze SQL-injectietruc. Stelt u zich eens voor dat u een tekstveld in een toepassing hebt, of deze nu browsergebaseerd of desktop is, en u geeft de waarde meteen door aan de procedure, en als u de bovenstaande truc toepast, dan zal dit zeker gebeuren.
Een voorbeeld om SQL-injectie te voorkomen
Nu zullen we de bovenstaande procedure aanpassen om de bindvariabele te gebruiken in plaats van de parameterwaarde samen te voegen en op deze manier kan geen enkele SQL-injectietruc werken.
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; /
Test de bovenstaande procedure normaal
SET SERVEROUTPUT ON; BEGIN prc_get_emp_sal_2 ('7566'); END; /
Uitgang
JONES -- 27706.89 PL/SQL procedure successfully completed.
Test de bovenstaande procedure met SQL-injectie
SET SERVEROUTPUT ON; BEGIN prc_get_emp_sal_2 ('1'' OR ''1''= ''1'); END; /
Mislukte uitvoer van SQL-injectie
Can not fetch any records for: 1' OR '1'= '1 PL/SQL procedure successfully completed.
Noteer het dus, als u PL/SQL-programma's maakt met dynamische SQL, gebruik dan de bindingsmethoden.