Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Przykład demonstrujący podatność na wstrzykiwanie SQL i zapobieganie jej w Oracle

Wszyscy wiemy, że jeśli jakikolwiek kod aplikacji jest źle napisany, to każdy może zhakować informacje za pomocą małej sztuczki, takiej jak SQL Injection. W tym poście podaję przykład, aby zademonstrować, w jaki sposób SQL Injection może być podatny na działanie aplikacji i jak można temu zapobiec.

Demonstracja jest oparta na tabeli EMP schematu SCOTT. Aby pobrać skrypt schematu SCOTT, kliknij poniższy link Pobierz skrypt schematu Scotta.

Przykład wykonywania wstrzykiwania SQL

W tej sekcji podam przykład procedury składowanej PL/SQL, która przyjmie parametr numer pracownika jako (p_empno) do wyświetlania wynagrodzenia dla tego pracownika. W kodzie używam konkatenacji wartości tego parametru (p_empno) w ciągu instrukcji SQL dla REF CURSOR, co nie jest zalecane i będzie przyczyną pomyślnego wstrzyknięcia SQL. Poniżej znajduje się procedura:

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

Teraz przetestujemy powyższą procedurę normalnie przekazując numer pracownika.

Test

SET SERVEROUTPUT ON;

BEGIN
   prc_get_emp_sal ('7566');
END;
/

Wyjście

JONES -- 27706.89
PL/SQL procedure successfully completed.

Do tej pory wszystko jest w porządku. Ponieważ poprawnie nazwaliśmy procedurę. Teraz zobaczymy, jak możemy zhakować powyższą procedurę, używając sztuczki SQL Injection, aby pobrać pensję wszystkich pracowników. Może czasami ty też chcesz to zrobić. Żartuję!

Test za pomocą wstrzykiwania SQL

SET SERVEROUTPUT ON;

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

Pomyślne wyjście wstrzykiwania 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.

Wow, teraz możesz zobaczyć pensję każdego pracownika za pomocą tej sztuczki SQL Injection. Wyobraź sobie, że masz pole tekstowe w aplikacji, niezależnie od tego, czy jest ona oparta na przeglądarce, czy na komputerze, i przekazujesz wartość od razu do procedury, a jeśli użyjesz powyższej sztuczki, na pewno tak się stanie.

Przykład zapobiegania wstrzykiwaniu SQL

Teraz zmodyfikujemy powyższą procedurę, aby użyć zmiennej bind zamiast łączenia wartości parametru, dzięki czemu żadna sztuczka SQL Injection nie zadziała.

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

Przetestuj powyższą procedurę normalnie

SET SERVEROUTPUT ON;

BEGIN
   prc_get_emp_sal_2 ('7566');
END;
/

Wyjście

JONES -- 27706.89
PL/SQL procedure successfully completed.

Przetestuj powyższą procedurę za pomocą wstrzykiwania SQL

SET SERVEROUTPUT ON;

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

Nieudane wyjście wstrzykiwania SQL

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

Więc zanotuj to, jeśli tworzysz programy PL/SQL używając dynamicznego SQL, użyj metod wiązania.

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Pobieranie danych wyjściowych z dbms_output.get_lines za pomocą JDBC

  2. Jak przekierować wyjście DBMS_OUTPUT.PUT_LINE do pliku?

  3. Scal/połącz wiele plików PDF w jeden plik PDF w Oracle za pomocą pakietu PLPDF_TOOLKIT PL/SQL

  4. Jak używać funkcji NVL() w Oracle

  5. Wyświetlaj nazwy wszystkich ograniczeń dla tabeli w Oracle SQL