sql >> Databasteknik >  >> RDS >> Oracle

Ett exempel för att demonstrera sårbarheten hos SQL-injektion och dess förebyggande i Oracle

Vi vet alla att om någon applikationskod är dåligt skriven, så kan vem som helst hacka informationen genom att använda ett litet trick som SQL Injection. I det här inlägget ger jag ett exempel för att visa hur SQL Injection kan vara sårbart för en applikation och hur du kan förhindra det.

Demonstrationen är baserad på SCOTT-schemats EMP-tabell. För att ladda ner SCOTT-schemaskriptet klicka på följande länk Ladda ner Scott Schema Script.

Ett exempel för att utföra SQL-injektion

I det här avsnittet ger jag ett exempel på en PL/SQL lagrad procedur som accepterar en parameter anställds nummer som (p_empno) för att visa lönen för den anställde. I koden använder jag sammanlänkningen av det parametervärdet (p_empno) i SQL-satssträngen för REF CURSOR, vilket inte rekommenderas och kommer att vara orsaken till framgångsrik SQL-injektion. Nedan är proceduren:

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 ska vi testa proceduren ovan normalt genom att skicka ett anställdsnummer.

Testa

SET SERVEROUTPUT ON;

BEGIN
   prc_get_emp_sal ('7566');
END;
/

Utdata

JONES -- 27706.89
PL/SQL procedure successfully completed.

Tills nu är allt bra. Eftersom vi korrekt kallade proceduren. Nu ska vi se hur vi kan hacka ovanstående procedur genom att använda SQL Injection-tricket för att hämta lönen för alla anställda. Kanske vill du ibland också göra det här. Skämt!

Testa med SQL Injection

SET SERVEROUTPUT ON;

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

Lyckad SQL-injektion

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, nu kan du se alla anställdas löner med detta SQL Injection-trick. Föreställ dig bara att du har ett textfält i en applikation oavsett om den är webbläsarbaserad eller stationär och du skickar värdet direkt till proceduren, och om du använder tricket ovan kommer detta säkert att hända.

Ett exempel för att förhindra SQL-injektion

Nu kommer vi att modifiera proceduren ovan för att använda bindningsvariabel istället för att sammanfoga parametervärdet och på så sätt kan inget SQL Injection-trick fungera.

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

Testa proceduren ovan normalt

SET SERVEROUTPUT ON;

BEGIN
   prc_get_emp_sal_2 ('7566');
END;
/

Utdata

JONES -- 27706.89
PL/SQL procedure successfully completed.

Testa proceduren ovan med SQL Injection

SET SERVEROUTPUT ON;

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

Misslyckad SQL Injection Output

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

Så notera det, om du skapar PL/SQL-program med dynamisk SQL, använd bindningsmetoderna.

  1. Hur jämför man den nuvarande raden med nästa och föregående rad i PostgreSQL?

  2. 12 MySQL/MariaDB Säkerhet Best Practices för Linux

  3. Konvertera siffror/siffror i ord för INR-valuta (indiska rupier) i Oracle PL/SQL

  4. INFOGA och UPPDATERA en post med hjälp av markörer i Oracle