※ 本記事は、Rob Watsonによる”23c SQL Firewall“を翻訳したものです。

2023年5月16日


概要

23cで導入されたSQLファイアウォールは、データベース内からの不正なSQLおよびSQLインジェクション攻撃を監視およびブロックすることで、一般的なデータベース攻撃に対するリアルタイムの保護を提供します。これは、受け入れられる一連のSQL文を取得し、それらのSQL文の許可リストを生成することによって行われます。許可リスト内の文の範囲外にある有効なSQLは、許可されているが違反リストに記録されているか、実行がブロックされている可能性があります。IPアドレスやコール・プログラムなどの環境コンテキストを適用して、信頼できるパスを介したアクセスを確保するために強制に使用することもできます。

次のブログ・エントリで、SQLファイアウォールの基本的な機能のいくつかをテストします。このブログではすべての機能については説明していませんが、SQLファイアウォールのドキュメントはここにあり、パッケージおよびタイプに関する参照はここにあります

使用方法

新機能をテストするため、ここでダウンロードできる23cの無料試用版をダウンロードし、小さなSwingbench負荷テスト・スキーマをインストールしました。ファイアウォール・パッケージは、コンテナまたはプラガブル・データベース・レベルで使用できます。プラガブル・データベース・レベルで試行することを選択しました。

23cデータベースには1つのPDBが付属しています。PDBにSOEというローカル・ユーザーを作成して、Swingbenchオーダー・エントリ・スキーマを所有しました。

sysユーザーを使用してファイアウォールを構成しましたが、新しいSQL_FIREWALL_ADMINロールを付与されたユーザーは、ファイアウォールを制御および保守できます。

SQLファイアウォールの設定

ステップ1はファイアウォールを有効にすることです…

exec DBMS_SQL_FIREWALL.ENABLE;

 

ファイアウォールを有効にすると、ファイアウォールをトレーニングする準備が整います。取得する内容を決定するために、取得プロセスを設定する必要があります。:

 

BEGIN
DBMS_SQL_FIREWALL.CREATE_CAPTURE(
username=>'SOE',
top_level_only=>FALSE,
start_capture=>TRUE
);
END;
/
  • ユーザー名: 取得に使用されるデータベース・ユーザーの名前です。この例では、SwingBenchスキーマ所有者SOEを使用しています。SOEユーザーが実行したコマンドがログに記録されます。
  • Top_level_only: SQL文が取得されるレベルを制御します。TRUEでは、トップレベルのSQL文のみの取得ログが生成されます。トップレベルの文だけでなく、PL/SQLモジュールから発行されたコマンドも取得するFLASEを使用しました。デフォルトはFALSEです。
  • Start_capture: デモンストレーション用、デフォルト値であるTRUEを使用しました。FALSEを選択すると、実際の取得を開始せずに取得を作成できます。FALSEを選択した場合、データを取得する準備ができたら、DBMS_SQL_FIREWALL.START_CAPTURE(‘SOE’)の実行が必要になります

SOEユーザーに対して実行されている取得で、Swingbenchが実行されていたコマンドが取得に登録できるように、SwingBenchロードを開始します。

 

./charbench -c test.xml -v users,tps,tpm,rsr

Time     Users       TPS     TPM      Errors  
14:21:28 [4/4]       491     13867    0       
14:21:29 [4/4]       517     14384    0       
14:21:30 [4/4]       446     14830    0       
14:21:31 [4/4]       447     15277    0       
14:21:32 [4/4]       469     15746    0       
14:21:33 [4/4]       504     16250    0       
14:21:34 [4/4]       492     16742    0       
14:21:35 [4/4]       482     17224    0       
14:21:36 [4/4]       505     17729    0    
….
….
….  

 

アプリケーションの実行に必要なすべてのコマンドが取得されたことを確認するために、ロードを約5分間実行したままにします。エラーは検出されませんでした。この負荷により、1秒間に約400から500のトランザクションが発生しました。

取得中に、DBA_SQL_FIREWALL_CAPTURE_LOGSビューを使用して、取得された文を確認できます。

 

select SQL_TEXT FROM DBA_SQL_FIREWALL_CAPTURE_LOGS where username='SOE';

SQL_TEXT
--------------------------------------------------------------------------------
BEGIN :1 :=ORDERENTRY.WAREHOUSEORDERSQUERY (:2,:3,:4); END;
BEGIN :1 :=ORDERENTRY.WAREHOUSEORDERSQUERY (:2,:3,:4); END;
BEGIN :1 :=ORDERENTRY.WAREHOUSEORDERSQUERY (:2,:3,:4); END;
BEGIN :1 :=ORDERENTRY.WAREHOUSEORDERSQUERY (:2,:3,:4); END;
UPDATE INVENTORIES SET QUANTITY_ON_HAND=QUANTITY_ON_HAND -:B1 WHERE PRODUCT_ID=:
B3 AND WAREHOUSE_ID=:B2
UPDATE INVENTORIES SET QUANTITY_ON_HAND=QUANTITY_ON_HAND -:B1 WHERE PRODUCT_ID=:
B3 AND WAREHOUSE_ID=:B2
SELECT CUSTOMER_ID,CUST_FIRST_NAME,CUST_LAST_NAME,NLS_LANGUAGE,NLS_TERRITORY,CRE
DIT_LIMIT,CUST_EMAIL,ACCOUNT_MGR_ID,CUSTOMER_SINCE,CUSTOMER_CLASS,SUGGESTIONS,DO
B,MAILSHOT,PARTNER_MAILSHOT,PREFERRED_ADDRESS,PREFERRED_CARD FROM CUSTOMERS where ROWNUM < :B1
…
…
…

 

取得は、このアプリケーションをデータベースに対して実行する必要がある正しいロードを表します。フル・ロードを取得すると、取得を停止できます。

 

exec DBMS_SQL_FIREWALL.STOP_CAPTURE('SOE');

PL/SQL procedure successfully completed.

 

取得された文から許可リストを生成できます。許可リストは、SOEユーザーが発行した認可されていないSQLをフィルタするためにファイアウォールによって使用されます。ユーザーに許可リストが存在するかどうか、および存在する場合はその中のステートメントを確認できます。

 

select SQL_TEXT from DBA_SQL_FIREWALL_ALLOWED_SQL where username = 'SOE';

no rows selected

 

取得から許可リストに文を移入するには、それらを生成する必要があります。

 

exec DBMS_SQL_FIREWALL.GENERATE_ALLOW_LIST('SOE');

PL/SQL procedure successfully completed.

 

前の選択を再実行すると、許可リストに取得された文が移入されたことがわかります。

 

select SQL_TEXT from DBA_SQL_FIREWALL_ALLOWED_SQL where username = 'SOE';

SQL_TEXT
--------------------------------------------------------------------------------
SELECT (TO_CHAR (SYSTIMESTAMP,:"SYS_B_00")||:"SYS_B_01"||SYS_CONTEXT (:"SYS_B_02
",:"SYS_B_03")||:"SYS_B_04"||SYS_CONTEXT (:"SYS_B_05",:"SYS_B_06")||:"SYS_B_07"|
|SYS_CONTEXT (:"SYS_B_08",:"SYS_B_09")||:"SYS_B_10"||SYS_CONTEXT (:"SYS_B_11",:"
SYS_B_12")||:"SYS_B_13"||SYS_CONTEXT (:"SYS_B_14",:"SYS_B_15")) FROM DUAL
INSERT INTO ORDER_ITEMS (ORDER_ID,LINE_ITEM_ID,PRODUCT_ID,UNIT_PRICE,QUANTITY,GI
FT_WRAP,CONDITION,ESTIMATED_DELIVERY) VALUES (:B4,:B3,:B2,:B1,:"SYS_B_0",:"SYS_B
_1",:"SYS_B_2",(SYSDATE +:"SYS_B_3"))
…
…
…

 

SOEユーザーに対してallow-listを設定すると、allow-listを有効にでき、allow-list内のSQLのみが実行できるようになります。

 

BEGIN​​
DBMS_SQL_FIREWALL.ENABLE_ALLOW_LIST(
username=>'SOE',
enforce=>DBMS_SQL_FIREWALL.ENFORCE_SQL,
block=>TRUE
);
END;
/
  • ユーザー名: 許可リストが作成されたユーザーを指定します。この値がNULLの場合、許可リストが有効になっていないすべてのユーザーの許可リストが有効になります。
  • 強制: このパラメータは、コンテキスト(IPアドレス、コール・プログラムなど)も強制に使用されるかどうかを指定します。指定可能な値は次のとおりです。:
    • DBMS_SQL.ENFORCE_CONTEXTは、構成済の許可されたコンテキストを強制します。
    • DBMS_SQL.ENFORCE_SQLは、構成済の許可されたSQLを強制します。
    • DBMS_SQL.ENFORCE_ALLでは、許可されたコンテキストと許可されたSQLの両方が強制されます。この設定はデフォルトです。
  • Block: TRUEに設定すると、ユーザーの許可リストにない実行済SQLがブロックされ、実行されません。このパラメータのデフォルト値はFALSEです。FALSEはすべてのSQL (一致および不一致)の実行を許可しますが、許可リストにないSQLは違反として記録されます。

最初に「I」を選択してSQLのみを強制し(環境コンテキストを無視)、ブロックを「TRUE」に設定して、許可リスト内の文のみがSOEユーザーによって実行されるようにします。

DBA_SQL_FIREWALL_ALLOW_LISTSを使用して作成された様々な許可リストのステータスを確認できます:

 

select username, status, generated_on, enforce, block from DBA_SQL_FIREWALL_ALLOW_LISTS

USERNAME   STATUS   GENERATED_ON ENFORCE BLOCK
---------- -------- --------------------------------------------------------------------------- --------------- --------------
SOE   ENABLED  02-MAY-23 17.20.34  ENFORCE_SQL Y

 

実行中のSQLファイアウォール

違反は、DBA_SQL_FIREWALL_VIOLATIONSビューで表示できます。

 

select SQL_TEXT, SQL_SIGNATURE, COMMAND_TYPE , IP_ADDRESS, OCCURRED_AT from DBA_SQL_FIREWALL_VIOLATIONS where username = 'SOE';

no rows selected

 

これで、ファイアウォールがTRUEで有効化され、SOEユーザーとして許可リストにないSQLは実行できません。SOEユーザーとして、許可リストにない文を実行すると、ファイアウォールによって違反がログに記録され、ブロックがTRUEに設定されているため、SQLの実行が停止されます。:

 

select customer_id from customers where rownum < 10;
select customer_id from customers where rownum < 10
*ERROR at line 1:
ORA-47605: SQL Firewall violation.      <<< The firewall has blocked it

 

違反ログを再度確認すると、ブロックされたSQLテキスト、IPアドレスおよび違反の時間など、違反もログに記録されていることがわかります。

 

select SQL_TEXT, IP_ADDRESS, OCCURRED_AT from DBA_SQL_FIREWALL_VIOLATIONS where username = 'SOE';

SQL_TEXT       IP_ADDRESS     OCCURRED_AT
---------------------------------------------------------------------- -------------------- ------------------------------
SELECT CUSTOMER_ID FROM CUSTOMERS WHERE ROWNUM <:"SYS_B_0"       10.0.0.253     02-MAY-23 15.54.11.167040 +00:

 

SOEユーザーとしてSwingbenchアプリケーションを再度実行すると、エラーは生成されません。

 

./charbench -c test.xml -v users,tps,tpm,errs

Time     Users       TPS     TPM      Errors   
15:59:06 [4/4]       217     217      0        
15:59:07 [4/4]       336     553      0        
15:59:08 [4/4]       384     937      0        
15:59:09 [4/4]       385     1322     0        
15:59:10 [4/4]       489     1707     0        
15:59:11 [4/4]       470     2196     0        
15:59:12 [4/4]       509     2666     0        
15:59:13 [4/4]       423     3175     0        
15:59:14 [4/4]       499     3598     0        
15:59:15 [4/4]       437     4097     0        
…
…
…

 

すべてのアプリケーションSQLを取得して追加したため、許可リストはエラーなしでアプリケーションが期待どおりに機能します。違反ログを再度確認しても、前の1つの違反のみが存在し、実行前に確認しました。:

 

select SQL_TEXT, IP_ADDRESS, OCCURRED_AT from DBA_SQL_FIREWALL_VIOLATIONS where username = ‘SOE’;

SQL_TEXT       IP_ADDRESS     OCCURRED_AT
———————————————————————- ——————– ——————————
SELECT CUSTOMER_ID FROM CUSTOMERS WHERE ROWNUM <:”SYS_B_0″       10.0.0.253     02-MAY-23 15.54.11.167040 +00:00

 

DBMS_SQL_FIREWALL.PURGE_LOGプロシージャを使用すると、フィルタ(ユーザー、時間範囲)によってログを完全にパージまたはパージできる違反ログをパージできます。

SOEスキーマ・オブジェクトへのアクセス権を持つ別のユーザーとして接続し、有効化された許可リストが設定されていない場合、そのユーザーはSOEスキーマ・オブジェクトに対して任意の文を実行できます。許可リストはデータベース・ユーザーに添付されます。ブロックできる文や違反として記録できる文を制御するだけでなく、コンテキストを制御することもできます。DBMS_SQL_FIREWALLパッケージは、信頼できるパスを介してデータにアクセスすることを保証するのに役立ちます。

DBMS_SQL_FIREWALLパッケージは、コンテキストを介して強制を制御できます。コンテキストは、ユーザーのIPアドレス、呼び出しを行うベースとなるOSプログラム、またはOSユーザーに基づきます。

現在のコンテキスト設定は、DBA_SQL_FIREWALL_ALLOWED_OS_PROGDBA_SQL_FIREWALL_OS_USERおよびDBA_SQL_FIREWQLL_ALLOWED_IP_ADDRビューで表示できます。

 

SQL> select * from DBA_SQL_FIREWALL_ALLOWED_OS_PROG;

USERNAME   OS_PROGRAM
---------- ---------------------------------------------------
SOE   JDBC Thin Client
SOE   sqlplus
SOE   sqlplus@instance-20230502-1247 (TNS V1-V3)

 

SOEユーザーについては、前述のOSプログラム・コンテキストのみが設定されています。SwingBenchアプリケーションは、JDBC Thinクライアント・ドライバを使用します。おそらく、SOEユーザーがアプリケーションを実行できるのみで、SQLPlusを介してSQL文にアクセスできないようにする必要があります。

そのためには、コンテキスト・リストを更新する必要があります。

 

BEGIN
DBMS_SQL_FIREWALL.DELETE_ALLOWED_CONTEXT(
username=>'SOE',
context_type=>DBMS_SQL_FIREWALL.OS_PROGRAM,
value=>'sqlplus');
END;
/

PL/SQL procedure successfully completed.

BEGIN  DBMS_SQL_FIREWALL.DELETE_ALLOWED_CONTEXT(
username=>'SOE',
context_type=>DBMS_SQL_FIREWALL.OS_PROGRAM,
value=>'sqlplus@instance-20230502-1247 (TNS V1-V3)');
END;
/


PL/SQL procedure successfully completed.
  • username: コンテキスト情報を削除するユーザー
  • context_type: 変更するコンテキストのタイプ。この場合は、プログラムを呼び出していますが、次のものを使用できます。:
    • DBMS_SQL_FIREWALL.OS_PROGRAM: 呼び出し元プログラム
    • DBMS_SQL_FIREWALL.IP_ADDRERSS: 発信者のIPアドレス
    • DBMS_SQL_FIREWALL.OS_USERNAME: コールを行うOSユーザー。
  • value: 削除するコンテキストの値

変更後、新しいコンテキスト情報を確認できます。:

 

select * from DBA_SQL_FIREWALL_ALLOWED_OS_PROG;

USERNAME   OS_PROGRAM
---------- ---------------------------------------------------
SOE   JDBC Thin Client

 

OSプログラムをコールするための新しいコンテキストでは、JDBC Thin Clinetからの接続のみが受け入れられます。

ここでは、適用ルールを更新してコンテキストを含める必要があります。このブログで最初にallow-listを有効にしたとき、ファイアウォールではSQL文のみを参照し、環境コンテキストは参照しないように指定しました。

 

BEGIN
DBMS_SQL_FIREWALL.UPDATE_ALLOW_LIST_ENFORCEMENT(
username=>'soe',
enforce=>DBMS_SQL_FIREWALL.ENFORCE_ALL,
block=>TRUE);
END;
/

PL/SQL procedure successfully completed.

  • username: 変更する許可リストのユーザー。この場合、SOEユーザー
  • enforce: この値は、DBMS_FIREWALL.ENFORCE_SQL (sqlのみ)からDBMS_FIREWALL.ENFORCE_ALL (sqlおよびcontexts)に変更します。
  • block: 許可リストにないSQLが実行されないように、ブロックはTRUEのままにします。

ファイアウォールでは、コンテキストとSQL文が考慮されるようになります。SOEユーザーとして、SQL文(SOEユーザーのallow-listに存在する文も含む)をsqlplusから実行しようとすると、コンテキストが原因で拒否されます。

SELECT ADDRESS_SEQ.NEXTVAL FROM DUAL;
SELECT ADDRESS_SEQ.NEXTVAL FROM DUAL

*ERROR at line 1:
ORA-47605: SQL Firewall violation. 

 

前述の問合せがallow-listにある場合でも、コマンドはsqlplusから発行され、受け入れられるコンテキストではなくなるためブロックされます。SwingBenchアプリケーションは、sqlplusではなくJDBCを使用するため、問題なく実行されます。

現在、アプリケーションを実行しているのはデータベースVMです。アプリケーションを別のVMで実行したい場合があります。現在許可されているIPアドレスを確認すると、次のように表示されます。:

select * from DBA_SQL_FIREWALL_ALLOWED_IP_ADDR;

USERNAME   IP_ADDRESS
---------- ------------
SOE   10.0.0.253

 

新しいアプリケーション・ホストvmのIPアドレスは10.0.0.250です。現在のIPアドレスを削除し、新しいIPアドレスを追加します。DELETE_ALLOWED_CONTEXTおよびADD_ALLOWED_CONTEXTプロシージャでは、DBMS_SQL_FIREWALL.IP_ADDRESSのcontext_typeを使用することに注意してください。

 

BEGIN
DBMS_SQL_FIREWALL.DELETE_ALLOWED_CONTEXT(
username=>'SOE',
context_type=>DBMS_SQL_FIREWALL.IP_ADDRESS,
value=>'10.0.0.253');
END;
/

PL/SQL procedure successfully completed.


BEGIN
DBMS_SQL_FIREWALL.ADD_ALLOWED_CONTEXT(
username=>'SOE',
context_type=>DBMS_SQL_FIREWALL.IP_ADDRESS,
value=>'10.0.0.250');
END;
/

PL/SQL procedure successfully completed.


select * from DBA_SQL_FIREWALL_ALLOWED_IP_ADDR;

USERNAME   IP_ADDRESS
---------- ------------
SOE   10.0.0.250

 

データベース・サーバー(古いIPアドレス)からアプリケーションを実行しようとすると、ユーザーのIPアドレスが10.0.0.250からではないため、ファイアウォールによってブロックされます。

 

 
/home/oracle/swingbench/bin/charbench -c test.xml -v users,tpm,tps,errs

Time     Users       TPM      TPS     Errors   
18:31:04 [0/4]       0        0       0        
May 04, 2023 6:31:05 PM com.dom.benchmarking.swingbench.kernel.SwingBenchConnectionFactory
getDedicatedConnection
SEVERE: getDedicatedConnection() threw exception
java.sql.SQLException: ORA-47605: SQL Firewall violation.   <<< Firewall blocked application
…
…
…

 

最後に

ほとんどのシナリオでは、Oracle Schedulerジョブは通常はユーザーによって実行されないため、SQLファイアウォールの適用から除外できます。

次の手順を使用して、FEATUREパラメータをDBMS_SQL_FIREWALL.SCHEDULER_JOB定数に設定することで、Oracle Schedulerの操作中にSQLファイアウォールの操作を有効または無効にできます。:

  • DBMS_SQL_FIREWALL.INCLUDEを使用すると、SQLファイアウォールは、Oracle Schedulerの操作中にSQLを取得したり、許可リストを強制できます。
  • DBMS_SQL_FIREWALL_EXCLUDEは、Oracle Schedulerの操作中にSQLファイアウォールがSQLを取得したり、許可リストを適用できないようにします。

次に例を示します。:

EXEC DBMS_SQL_FIREWALL.EXCLUDE (DBMS_SQL_FIREWALL.SCHEDULER_JOB);

 

まとめ

これはSQLファイアウォールの機能の基本的な概要にすぎませんが、これによってセキュリティが強化され、信頼できるパスを介したアクセスが確実に確保されることが望ましいと考えられます。完全な機能については、ドキュメントを参照してください。