はじめに

こんにちは。Oracle Databaseの検証チームです。
今回は、Oracle 23aiの新機能「SQL Firewall」について検証してみました。

名前の通り、許可の無いSQLをブロックするセキュリティ機能となります。
こちらの機能は、以前のバージョンでは別製品「Audit Vault and Database Firewall」に梱包されておりました。
23aiでは、Database製品に内包されているため、より多くのユーザーにご利用いただき易くなったかと思われます。

ライセンスについて

ご利用にあたり、以下のどちらかのライセンスが必要となります。

しかしながら、Oracle Cloudをご利用のユーザーは、以下のサービスに「Oracle Database Vault」ライセンスが含まれておりますので、直ぐにご利用いただけます

  • BaseDB EE-HP
  • BaseDB EE-EP
  • ExaDB-D

参考URL
1.4 Oracle Database Options and Their Permitted Features

SQL Firewallの機能説明

SQL Firewallと使用方法

SQL Firewallは、ターゲットとなるスキーマに対して「SQL許可リスト」を作成し、それを有効にすることで許可のない不正なSQLをブロックすることができるという機能です。
実際に使い方を見ていきましょう。

マニュアルに記載されている使い方は、3ステップです。

  • ステップ1.SQLファイアウォールを有効にします。
  • ステップ2. 通常のSQLアクティビティを取得します。
  • ステップ3.許可リストを有効にして強制します。

参考URL
13.1.3 Oracle SQL Firewallの開始

許可リストの作成

平時に実行されているSQLのキャプチャ(SQL文、IPアドレス、ユーザーなど)を取得し、キャプチャログを元にリストを作成できるようです。
「許可リスト」と聞くと、時間をかけてコツコツとリストを作成していくイメージがありましたが、これなら簡単に作成できそうですね。

SQL文の標準化

SQLのWHERE句の条件は、自動で標準化された形式でキャプチャに保存されるようです。
バインド変数を使わずに、リテラルのSQL文を実行しているシステムでも安心してご利用いただけますね。

– 例
実行したSQL : SELECT * FROM TABLE WHERE COL1=123
保存されるSQL: SELECT * FROM TABLE WHERE COL1=:”SYS_B_0″

許可リストのチューニング

キャプチャから作成したSQLリストは、作成後にSQL文やIPアドレスの追加・削除を自由に行うことが可能です。
詳しくは、DBMS_SQL_FIREWALLパッケージのマニュアルをご参考になさってください。

参考URL
176.4 DBMS_SQL_FIREWALLサブプログラムの要約

検証してみよう

では、実際にSQL Firewallを検証していきましょう。
今回の目標は、「許可リストを作成した後に、許可のないSQLを実行してブロックされることを検証する」ことです。

環境は、OCI BaseDBサービスを使用します。
テスト用のスキーマとして、SwingBenchという負荷掛けツールのSOEスキーマを利用しようと思います。
参考URL SwingBench:https://www.dominicgiles.com/swingbench/

SQLファイアウォールの有効化

対象のスキーマが属しているPDBへ接続し、以下のプロシージャを実行します。
※SQL_FIREWALL_ADMIN権限が必要です。本検証ではsysdba権限を使用し、PDB1に接続します。

oracle$ sqlplus sys@PDB1 as sysdba
(パスワードを求められるため、入力)

SQL> exec DBMS_SQL_FIREWALL.ENABLE;

PL/SQL procedure successfully completed.

キャプチャの開始

キャプチャの作成と開始を同時に行います。
本検証の対象のスキーマは、”SOE”スキーマです。

SQL> BEGIN
2 DBMS_SQL_FIREWALL.CREATE_CAPTURE (
3 username => 'SOE',
4 top_level_only => TRUE,
5 start_capture => TRUE
6 );
7 END;
8 /

PL/SQL procedure successfully completed.

平時のSQL実行

SwingBenchで負荷掛けしてみます。
内部でSELECT文がランダムで実行されているようですので、それらをキャプチャログに保管します。

/opt/swingbench/bin/charbench -c /opt/swingbench/configs/SOE_Server_Side_V2.xml -cs //basedb-tky:1521/pdb1.sub08230824010.vcndbteamtokyo.oraclevcn.com u soe -p <パスワード> -v users,tpm,tps,vresp -intermin 0 -intermax 0 -min 0 -max 0 -uc 50 -di SQ,WQ,WA -rt 00:01.000
Swingbench
Author : Dominic Giles
Version : 2.7.0.1511

Results will be written to results.xml
Expected Benchmark Runtime is set to 1 minute.

Time Users TPM TPS NCR UCD BP OP PO BO SQ WQ WA
16:33:54 [0/50] 0 0 0 0 0 0 0 0 0 0 0
16:33:56 [6/50] 0 0 0 0 0 0 0 0 0 0 0
16:33:57 [22/50] 0 0 0 0 0 0 0 0 0 0 0
16:33:58 [34/50] 57 57 248 325 194 248 0 237 0 0 0
16:33:59 [36/50] 355 298 128 198 57 131 136 68 0 0 0

:
(中略)
:
16:35:05 [50/50] 36159 560 136 78 24 171 118 84 0 0 0
16:35:06 [50/50] 36215 546 114 64 18 166 106 124 0 0 0
16:35:07 [50/50] 36178 433 194 92 28 208 171 139 0 0 0
Saved results to results00004.xml
16:35:08 [0/50] 36244 559 108 58 24 154 104 100 0 0 0
Completed Run.

キャプチャの終了/キャプチャログの確認

キャプチャログは、「DBA_SQL_FIREWALL_CAPTURE_LOGS」ディクショナリ・ビューから参照できます。

SQL> exec DBMS_SQL_FIREWALL.STOP_CAPTURE('SOE');

PL/SQL procedure successfully completed.

SQL> set markup csv on
SQL> select * from DBA_SQL_FIREWALL_CAPTURE_LOGS where username = 'SOE';

許可リストの作成

SQL> exec DBMS_SQL_FIREWALL.GENERATE_ALLOW_LIST('SOE');

PL/SQL procedure successfully completed.

SQL> select * from DBA_SQL_FIREWALL_ALLOWED_SQL;

SQL> select * from DBA_SQL_FIREWALL_ALLOW_LISTS;
"USERNAME","GENERATED_ON","STATUS","STATUS_UPDATED_ON","TOP_LEVEL_ONLY","ENFORCE","BLOCK"
"SOE","06-NOV-24 04.48.57.812273 PM +09:00","DISABLED","06-NOV-24 04.48.57.812273 PM +09:00","Y","ENFORCE_ALL","N"

DBA_SQL_FIREWALL_ALLOW_LISTS.BLOCKが”N”なので、まだ許可リストが有効になっていないことを示しています。
また、「DBA_SQL_FIREWALL_ALLOWED_SQL」ディクショナリー・ビューの他にも以下のビューが用意されていますので、必要に応じて参照します。

  • select * from DBA_SQL_FIREWALL_ALLOWED_IP_ADDR;
  • select * from DBA_SQL_FIREWALL_ALLOWED_OS_PROG;
  • select * from DBA_SQL_FIREWALL_ALLOWED_OS_USER;

許可リストの有効化

SQL> BEGIN
2 DBMS_SQL_FIREWALL.ENABLE_ALLOW_LIST(
3 username => 'SOE',
4 enforce => DBMS_SQL_FIREWALL.ENFORCE_ALL,
5 block => TRUE
6 );
7 END;
8 /

PL/SQL procedure successfully completed.

SQL> select BLOCK from DBA_SQL_FIREWALL_ALLOW_LISTS;
"BLOCK"
"Y"

許可のないSQLがブロックされることを確認

これで、SQL Firewallが機能している状態となりました。
ではSOEスキーマで適当なSQL文を実行してみます。

[oracle@basedb-tky ~]$ sqlplus SOE@PDB1

SQL*Plus: Release 23.0.0.0.0 - for Oracle Cloud on Wed Nov 6 17:24:31 2024
Version 23.4.1.24.06

Copyright (c) 1982, 2024, Oracle. All rights reserved.

Enter password:
Last Successful login time: Wed Nov 06 2024 17:19:22 +09:00

Connected to:
Oracle Database 23ai Enterprise Edition Release 23.0.0.0.0 - for Oracle Cloud
Version 23.4.1.24.06

SQL> select * from SOE.CUSTOMERS;
select * from SOE.CUSTOMERS
*
ERROR at line 1:
ORA-47605: SQL Firewall violation
Help: https://docs.oracle.com/error-help/db/ora-47605/

見事、カスタマー情報を外敵からブロックしました。

おわりに

以上でSQL Firewallの紹介と検証は完了です。

設定には実際にSQLを実行する必要がありますが非常に利用し易く、
一度設定してしまえば許可したSQL以外は実行できないので、セキュリティのリスク軽減につながると思います。

最後までお読みいただきありがとうございました!

おまけ:ログインすらブロックされる場合

検証の章では省きましたが、SQL許可リストを有効化したあとに、SQL*PlusでのログインがFirewallで拒否されるようになってしまいました
どうやらSwingBenchはJDBCプログラムを使用しているため、別途SQL*Plusプログラムでのログイン操作もキャプチャしておく必要があるみたいですね。

同じような事象になった人のために、SQL許可リストを更新するコマンドを記載させていただきます。

-- SQL許可リストを無効化
BEGIN
DBMS_SQL_FIREWALL.DISABLE_ALLOW_LIST ( 
username => 'SOE'
);
END;
/

-- SQL許可リストが無効されたことを確認
select BLOCK from DBA_SQL_FIREWALL_ALLOW_LISTS;

-- キャプチャの開始
BEGIN
DBMS_SQL_FIREWALL.START_CAPTURE ( 
username => 'SOE'
);
END;
/

-- ★ログインのキャプチャを記録
sqlplus SOE@PDB1 

-- キャプチャの終了
exec DBMS_SQL_FIREWALL.STOP_CAPTURE('SOE');

-- 既存の許可リストに追加
BEGIN
DBMS_SQL_FIREWALL.APPEND_ALLOW_LIST (
username => 'SOE',
source => DBMS_SQL_FIREWALL.CAPTURE_LOG
);
END;
/

-- 許可リストの有効化
BEGIN
DBMS_SQL_FIREWALL.ENABLE_ALLOW_LIST(
username => 'SOE',
enforce => DBMS_SQL_FIREWALL.ENFORCE_ALL,
block => TRUE
);
END;
/

以上、ご拝読くださりありがとうございました!

投稿者プロフィール

技術チーム
技術チーム
DBひとりでできるもんを盛り上げるべく、技術チームが立ち上がり早6年。ひとりでできるもんと言いつつ、技術者が読んでプッとなるような、極めてピンポイントでマニアックな技術ネタを執筆しています!