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