Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Ein Beispiel zur Veranschaulichung der Schwachstelle der SQL-Injection und ihrer Verhinderung in Oracle

Wir alle wissen, dass wenn ein Anwendungscode schlecht geschrieben ist, jeder die Informationen hacken kann, indem er einen kleinen Trick wie SQL Injection anwendet. In diesem Beitrag gebe ich ein Beispiel, um zu demonstrieren, wie SQL Injection für eine Anwendung anfällig sein könnte und wie Sie dies verhindern können.

Die Demonstration basiert auf der EMP-Tabelle des SCOTT-Schemas. Um das SCOTT-Schemaskript herunterzuladen, klicken Sie auf den folgenden Link Download Scott Schema Script.

Ein Beispiel zur Durchführung einer SQL-Injection

In diesem Abschnitt gebe ich ein Beispiel für eine gespeicherte PL/SQL-Prozedur, die eine Parameter-Mitarbeiternummer als (p_empno) akzeptiert, um das Gehalt für diesen Mitarbeiter anzuzeigen. Im Code verwende ich die Verkettung dieses Parameterwerts (p_empno) in der SQL-Anweisungszeichenfolge für REF CURSOR, was nicht empfohlen wird und die Ursache für eine erfolgreiche SQL-Injektion sein wird. Unten ist das Verfahren:

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

Jetzt werden wir das obige Verfahren normal testen durch Übergabe einer Mitarbeiternummer.

Test

SET SERVEROUTPUT ON;

BEGIN
   prc_get_emp_sal ('7566');
END;
/

Ausgabe

JONES -- 27706.89
PL/SQL procedure successfully completed.

Bis jetzt ist alles in Ordnung. Weil wir die Prozedur richtig aufgerufen haben. Jetzt werden wir sehen, wie wir das obige Verfahren hacken können, indem wir den SQL-Injection-Trick verwenden, um das Gehalt aller Mitarbeiter abzurufen. Vielleicht möchten Sie das auch manchmal tun. Scherz!

Test mit SQL-Injection

SET SERVEROUTPUT ON;

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

Erfolgreiche SQL-Injection-Ausgabe

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, jetzt können Sie mit diesem SQL-Injection-Trick das Gehalt jedes Mitarbeiters sehen. Stellen Sie sich vor, Sie haben ein Textfeld in einer Anwendung, egal ob browserbasiert oder Desktop, und Sie übergeben den Wert direkt an die Prozedur, und wenn Sie den obigen Trick anwenden, dann wird dies sicherlich passieren.

Ein Beispiel zur Verhinderung von SQL-Injection

Jetzt werden wir die obige Prozedur ändern, um eine Bindevariable zu verwenden, anstatt den Parameterwert zu verketten, und auf diese Weise kann kein SQL-Injection-Trick funktionieren.

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

Testen Sie das obige Verfahren normal

SET SERVEROUTPUT ON;

BEGIN
   prc_get_emp_sal_2 ('7566');
END;
/

Ausgabe

JONES -- 27706.89
PL/SQL procedure successfully completed.

Testen Sie das obige Verfahren mit SQL Injection

SET SERVEROUTPUT ON;

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

Fehlerhafte SQL-Injection-Ausgabe

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

Notieren Sie sich also, wenn Sie PL/SQL-Programme mit dynamischem SQL erstellen, verwenden Sie die Bindungsmethoden.