Oracle
 sql >> база данни >  >> RDS >> Oracle

Пример за демонстриране на уязвимостта на SQL инжекцията и нейното предотвратяване в Oracle

Всички знаем, че ако кодът на приложението е лошо написан, тогава всеки може да хакне информацията, като използва малък трик като 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, използвайте методите за свързване.

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Проблем с променливите за свързване на Oracle, които не използват правилно индекса

  2. Как да използвате виртуален индекс в Oracle Database

  3. В Oracle AS псевдонимът не работи

  4. Изберете count(*) от множество таблици

  5. Справяне с грешката в Drop Column в Oracle 18c и 19c