Oracle AI Database 26ai / SQL Firewall / インジェクション対策 / セキュリティ
本記事では、Oracle Database 26ai (23ai) の新機能「SQL Firewall」の導入手順を解説します。 以前は「Audit Vault and Database Firewall (AVDF)」という別製品が必要でしたが、26aiからはデータベース・カーネルに内包され、標準機能としてより手軽に利用可能になりました。
今回は、許可リストの作成からブロック動作の検証、さらに「必要な操作(ログイン等)までブロックされてしまった場合」のリカバリ手順までを網羅して検証します。
検証環境に関する注記: 本記事の検証結果およびログは Oracle Database 26ai Free Release 23.26.0.0.0 環境にて取得したものです。正式版(Enterprise Edition等)や将来のバージョンでは、動作や出力メッセージが異なる可能性があります。あらかじめご了承ください。
💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?
Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?
1. はじめに・ライセンスについて
SQL Firewall は、許可のないSQLをブロックするセキュリティ機能です。
ライセンス要件
ご利用にあたり、以下のいずれかのライセンスが必要です。
- Oracle Database Vault
- Oracle Audit Vault and Database Firewall
ただし、Oracle Cloud (OCI) をご利用の場合、以下のサービスには「Oracle Database Vault」ライセンスが含まれているため、追加費用なしで利用可能です。
- BaseDB EE-HP (High Performance)
- BaseDB EE-EP (Extreme Performance)
- ExaDB-D (Exadata Database Service)
Note: ライセンスの詳細や適用条件は変更される可能性があります。最新の正確な情報については、必ず Oracle公式ドキュメント(ライセンス情報) をご確認ください。
2. SQL Firewall の仕組み(SQLの標準化)
SQL Firewall はキャプチャしたSQLを「許可リスト」として登録しますが、この際、SQL文中のリテラル値(具体的な数値や文字列)は自動的にシステム変数(:"SYS_B_0" 等)に置換され、標準化されます。
- 実行したSQL:
SELECT * FROM products WHERE id = 123 - 保存されるSQL:
SELECT * FROM products WHERE id = :"SYS_B_0"
これにより、ID値が変わるたびに別のSQLとして登録する必要がなく、バインド変数を使用していないアプリケーションでも柔軟に対応可能です。
3. 検証環境の準備
検証用のユーザー FW_TEST とテーブルを作成します。 ※本手順は PDB (FREEPDB1 等) 上で実行することを前提としています。
-- PDB管理者(SYSなど)で接続
CONN sys/password@FREEPDB1 AS SYSDBA
-- ユーザー作成と権限付与
CREATE USER fw_test IDENTIFIED BY Password_123;
GRANT CONNECT, RESOURCE TO fw_test;
GRANT UNLIMITED TABLESPACE TO fw_test;
-- テストデータ作成
CREATE TABLE fw_test.products (
id NUMBER PRIMARY KEY,
name VARCHAR2(50),
price NUMBER
);
INSERT INTO fw_test.products VALUES (101, 'Mouse', 3000);
INSERT INTO fw_test.products VALUES (102, 'Keyboard', 8000);
COMMIT;
4. 検証ステップ
Step 1: SQLファイアウォールの有効化
まず、PDBレベルで機能を有効にします。 ※ SQL_FIREWALL_ADMIN 権限または SYSDBA 権限が必要です。
-- PDB管理者で実行
EXEC DBMS_SQL_FIREWALL.ENABLE;
-- 確認(ENABLED であること)
SELECT status FROM DBA_SQL_FIREWALL_STATUS;
実行ログ例:
SQL> SELECT status FROM DBA_SQL_FIREWALL_STATUS;
STATUS
--------
DISABLED
SQL> EXEC DBMS_SQL_FIREWALL.ENABLE;
PL/SQL procedure successfully completed.
SQL> SELECT status FROM DBA_SQL_FIREWALL_STATUS;
STATUS
--------
ENABLED
Step 2: キャプチャの開始
検証対象ユーザー FW_TEST のSQLキャプチャを開始します。 start_capture => TRUE を指定することで、作成と同時にキャプチャを開始できます。
-- 既存設定がある場合はリセット(念のため)
BEGIN
BEGIN DBMS_SQL_FIREWALL.STOP_CAPTURE('FW_TEST'); EXCEPTION WHEN OTHERS THEN NULL; END;
BEGIN DBMS_SQL_FIREWALL.DROP_CAPTURE('FW_TEST'); EXCEPTION WHEN OTHERS THEN NULL; END;
BEGIN DBMS_SQL_FIREWALL.DISABLE_ALLOW_LIST('FW_TEST'); EXCEPTION WHEN OTHERS THEN NULL; END;
BEGIN DBMS_SQL_FIREWALL.DROP_ALLOW_LIST('FW_TEST'); EXCEPTION WHEN OTHERS THEN NULL; END;
END;
/
-- キャプチャ作成と開始
BEGIN
DBMS_SQL_FIREWALL.CREATE_CAPTURE (
username => 'FW_TEST',
top_level_only => TRUE,
start_capture => TRUE -- ★ここで即時開始
);
END;
/
実行ログ例:
SQL> BEGIN
2 BEGIN DBMS_SQL_FIREWALL.STOP_CAPTURE('FW_TEST'); EXCEPTION WHEN OTHERS THEN NULL; END;
3 BEGIN DBMS_SQL_FIREWALL.DROP_CAPTURE('FW_TEST'); EXCEPTION WHEN OTHERS THEN NULL; END;
4 BEGIN DBMS_SQL_FIREWALL.DISABLE_ALLOW_LIST('FW_TEST'); EXCEPTION WHEN OTHERS THEN NULL; END;
5 BEGIN DBMS_SQL_FIREWALL.DROP_ALLOW_LIST('FW_TEST'); EXCEPTION WHEN OTHERS THEN NULL; END;
6 END;
7 /
PL/SQL procedure successfully completed.
SQL> BEGIN
2 DBMS_SQL_FIREWALL.CREATE_CAPTURE (
3 username => 'FW_TEST',
4 top_level_only => TRUE,
5 start_capture => TRUE
6 );
7 END;
8 /
PL/SQL procedure successfully completed.
SQL>
Step 3: 平時のSQL実行(学習)
ここで行った操作が「正常なアクセス」として許可リストに登録されます。 FW_TEST ユーザーでログインし、正規のSQLを実行します。
-- FW_TESTで接続
CONN fw_test/Password_123@FREEPDB1
-- 正規のSQLを実行(これらが許可されます)
SELECT * FROM products WHERE id = 101;
SELECT name, price FROM products;
実行ログ例:
SQL> CONN fw_test/Password_123@FREEPDB1
Connected.
SQL> SHOW CON_NAME
CON_NAME
------------------------------
FREEPDB1
SQL> SELECT * FROM products WHERE id = 101;
ID NAME PRICE
---------- ---------------------------------------- ----------
101 Mouse 3000
SQL> SELECT name, price FROM products;
NAME PRICE
-------------------------------------------------- ----------
Mouse 3000
Keyboard 8000
SQL>
Step 4: キャプチャ終了とログ確認
十分なログが取れたらキャプチャを停止し、記録された内容を確認します。
-- SYSで再接続
CONN sys/password@FREEPDB1 AS SYSDBA
-- キャプチャ停止
EXEC DBMS_SQL_FIREWALL.STOP_CAPTURE('FW_TEST');
-- キャプチャログの確認(CSV形式で見やすく出力)
-- client_program も確認すると接続元(sqlplus, jdbc等)が判別しやすくなります
SET MARKUP CSV ON
SELECT command_type, sql_text FROM DBA_SQL_FIREWALL_CAPTURE_LOGS WHERE username = 'FW_TEST';
SET MARKUP CSV OFF
💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?
Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?
Step 5: 許可リストの作成と確認
キャプチャログを元に、許可リスト(Allow List)を生成します。
-- リスト生成
EXEC DBMS_SQL_FIREWALL.GENERATE_ALLOW_LIST('FW_TEST');
-- 生成されたSQLリストの確認
-- リテラル値が :"SYS_B_0" などに置換されていることを確認してください
SELECT sql_text FROM DBA_SQL_FIREWALL_ALLOWED_SQL WHERE username = 'FW_TEST';
-- リストの設定状態確認
-- まだ有効化していないため、BLOCK='N' となっています
SELECT username, status, enforce, block FROM DBA_SQL_FIREWALL_ALLOW_LISTS WHERE username = 'FW_TEST';
実行ログ例:
SQL> show con_name
CON_NAME
------------------------------
FREEPDB1
SQL> EXEC DBMS_SQL_FIREWALL.GENERATE_ALLOW_LIST('FW_TEST');
PL/SQL procedure successfully completed.
SQL> SELECT sql_text FROM DBA_SQL_FIREWALL_ALLOWED_SQL WHERE username = 'FW_TEST';
SQL_TEXT
--------------------------------------------------------------------------------------
SELECT NAME,PRICE FROM PRODUCTS
SELECT * FROM PRODUCTS WHERE ID=:"SYS_B_0"
SELECT SYS_CONTEXT (:"SYS_B_0",:"SYS_B_1") NAME_COL_PLUS_PDB_CONTAINER FROM SYS.DUAL
SELECT DECODE (USER,:"SYS_B_0",XS_SYS_CONTEXT (:"SYS_B_1",:"SYS_B_2"),USER) FROM SYS.DUAL
SQL> SELECT username, status, enforce, block FROM DBA_SQL_FIREWALL_ALLOW_LISTS WHERE username = 'FW_TEST';
USERNAME STATUS ENFORCE BLOCK
---------- -------- --------------- --------------
FW_TEST DISABLED ENFORCE_ALL N
SQL>
Step 6: 許可リストの有効化
いよいよ防御モードを有効にします。 enforce => ENFORCE_ALL に加え、block => TRUE を明示的に指定します。
BEGIN
DBMS_SQL_FIREWALL.ENABLE_ALLOW_LIST(
username => 'FW_TEST',
enforce => DBMS_SQL_FIREWALL.ENFORCE_ALL, -- 強制ブロックモード
block => TRUE -- ★ここが重要
);
END;
/
-- 設定後の確認(BLOCK='Y' になっていること)
SELECT username, status, enforce, block FROM DBA_SQL_FIREWALL_ALLOW_LISTS WHERE username = 'FW_TEST';
実行ログ例:
SQL> BEGIN
2 DBMS_SQL_FIREWALL.ENABLE_ALLOW_LIST(
3 username => 'FW_TEST',
4 enforce => DBMS_SQL_FIREWALL.ENFORCE_ALL,
5 block => TRUE
6 );
7 END;
8 /
PL/SQL procedure successfully completed.
SQL> SELECT username, status, enforce, block FROM DBA_SQL_FIREWALL_ALLOW_LISTS WHERE username = 'FW_TEST';
USERNAME STATUS ENFORCE BLOCK
---------- -------- --------------- --------------
FW_TEST ENABLED ENFORCE_ALL Y
SQL>
Step 7: ブロック動作の確認
許可されていないSQL(インジェクション攻撃など)を実行し、エラーになることを確認します。
-- FW_TESTで接続
CONN fw_test/Password_123@FREEPDB1
-- [OK] リストにある正規SQL
SELECT * FROM products WHERE id = 101;
-- [NG] 未知のSQL(インジェクション攻撃)
SELECT * FROM products WHERE id = 101 OR 1=1;
実行ログ例:
SQL> CONN fw_test/Password_123@FREEPDB1
Connected.
SQL> SHOW CON_NAME
CON_NAME
------------------------------
FREEPDB1
SQL> SELECT * FROM products WHERE id = 101;
ID NAME PRICE
---------- -------------------------------------------------- ----------
101 Mouse 3000
SQL> SELECT * FROM products WHERE id = 101 OR 1=1;
SELECT * FROM products WHERE id = 101 OR 1=1
*
ERROR at line 1:
ORA-47605: SQL Firewall violation
Help: https://docs.oracle.com/error-help/db/ora-47605/
SQL>
このエラーが発生すれば、Firewallは見事に機能しています!
5. 【おまけ】ログインすらブロックされる場合の対処法
SQL Firewallを有効化した後、「SQL*Plusでのログイン自体が拒否される」 ようになってしまうことがあります。 これは、アプリケーション(JDBC等)とツール(SQLPlus)で接続時の内部SQLやプログラム情報が異なるため、SQLPlusでのログイン操作が「未知の操作」とみなされるためです。
その場合、以下の手順で許可リストに不足分を追加(Append)します。
手順:不足している操作を追加学習させる
- 一時的にリストを無効化
-- SYSで実行 EXEC DBMS_SQL_FIREWALL.DISABLE_ALLOW_LIST('FW_TEST'); - 追加キャプチャの開始
EXEC DBMS_SQL_FIREWALL.START_CAPTURE('FW_TEST'); - ブロックされていた操作(ログイン等)を実行 別のターミナル等で
sqlplus fw_test/...を実行し、正常にログインできることを確認します。 - キャプチャ停止とリストへの追加(APPEND)
GENERATEではなくAPPEND_ALLOW_LISTを使い、既存リストに差分を追加します。-- キャプチャ停止 EXEC DBMS_SQL_FIREWALL.STOP_CAPTURE('FW_TEST'); -- ★ここがポイント:キャプチャログの内容を既存リストに追加 BEGIN DBMS_SQL_FIREWALL.APPEND_ALLOW_LIST ( username => 'FW_TEST', source => DBMS_SQL_FIREWALL.CAPTURE_LOG ); END; / - 再度、許可リストを有効化
BEGIN DBMS_SQL_FIREWALL.ENABLE_ALLOW_LIST( username => 'FW_TEST', enforce => DBMS_SQL_FIREWALL.ENFORCE_ALL, block => TRUE ); END; /
これで、既存のアプリケーション通信を阻害することなく、運用ツールの操作も許可できるようになります。
6. FAQ
Q1: 以前の SQL Firewall (AVDF) と何が違いますか? A: 最大の違いは 「カーネル統合型」 である点です。データベースエンジン内部で動作するため、ネットワーク層のプロキシ型(AVDF)と比較してレイテンシが極めて低く、暗号化された通信やバイパス攻撃にも強いというメリットがあります。ただし、監査レポート機能などは AVDF の方が充実しています。
Q2: 許可リストの追加は手動でできますか? A: はい。DBMS_SQL_FIREWALL.ADD_ALLOWED_SQL プロシージャを使用して、特定のSQLテキストを手動でリストに追加することが可能です。ただし、構文やリテラル置換のルールを合わせる必要があるため、基本的にはキャプチャ機能(APPEND_ALLOW_LIST)の使用をお勧めします。
Q3: パフォーマンスへの影響は? A: SQLの解析(Parse)フェーズで照合を行うため、実行時オーバーヘッドは非常に小さい設計になっています。しかし、許可リストが数十万件レベルに膨れ上がるとメモリ使用量や検索コストに影響が出る可能性があります。不要なSQLは定期的に整理することが推奨されます。
7. まとめ
- Oracle 26ai (23ai) では、SQL Firewall が標準機能として利用可能になりました。
- ホワイトリスト方式(許可したSQL以外は拒否)により、未知のSQLインジェクション攻撃を確実に防ぐことができます。
- 導入は 「有効化 → 学習(キャプチャ) → リスト生成 → 防御(ブロック)」 のシンプルな4ステップで完了します。
- 万が一必要な操作がブロックされた場合でも、追記学習(Append) で柔軟に対応可能です。
SQL Firewall は、一度設定してしまえば「許可したSQL以外は一切実行できない」という強力なセキュリティ盤石となります。ぜひ活用してみてください。
[参考]
DBMS_SQL_FIREWALL
💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?
Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?



コメント