sql >> データベース >  >> RDS >> Oracle

OracleにおけるSQLインジェクションの脆弱性とその防止を実証する例

    アプリケーションコードの記述が不十分な場合、SQLインジェクションなどのちょっとしたトリックを使用して、だれでも情報をハッキングできることは誰もが知っています。この投稿では、SQLインジェクションがアプリケーションに対してどのように脆弱である可能性があり、どのようにそれを防ぐことができるかを示す例を示しています。

    デモンストレーションは、SCOTTスキーマのEMPテーブルに基づいています。 SCOTTスキーマスクリプトをダウンロードするには、次のリンクをクリックしてください。Scottスキーマスクリプトのダウンロード。

    SQLインジェクションを実行する例

    このセクションでは、パラメータの従業員番号を(p_empno)として受け入れ、その従業員の給与を表示するPL/SQLストアドプロシージャの例を示します。コードでは、REF CURSORのSQLステートメント文字列でそのパラメーター(p_empno)値の連結を使用しています。これは推奨されておらず、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.

    したがって、動的SQLを使用してPL / SQLプログラムを作成する場合は、バインディング・メソッドを使用することに注意してください。

    1. Oracleの日付フィールドから日付値のみを抽出するにはどうすればよいですか?

    2. SQL Server(T-SQL)で高度なサーバー構成オプションを表示する

    3. PostgreSQLで読み取り専用ユーザーを作成する方法

    4. ORDER BYにifステートメントを追加できますか?