はじめに
Oracle SQL Firewallを使うと、「このDBユーザーは普段どのようなSQLを実行するか」を学習し、その許可リストにないSQLを検知・遮断できます。
この記事では、Autonomous AI Database(以下、ADB)に専用の検証ユーザーを作成し、学習 → 許可リスト生成 → 監視 → 遮断 → 許可SQL追加を実際に試しました。さらに、SQLの条件値を変えたとき、バインド変数を使ったとき、接続元の条件を外れたときの動作も確認します。
検証日は2026年10月23日です。掲載している商品データはすべて架空です。実際の接続先・IPアドレス・個人のOSユーザー名・鍵・パスワードは掲載していません。<GENERATED_PASSWORD> などは公開用の置換表記です。
1. SQL Firewallとは
SQL Firewallは、Oracle Databaseの内部でSQLや接続の条件を確認するセキュリティ機能です。DBユーザーごとの許可リストを使い、普段と異なるSQLや想定外の接続を検知・遮断します。Oracle公式:SQL Firewallについて
たとえば、商品検索だけをするアプリが次のSQLを使っているとします。
SELECT product_id, product_name
FROM products
WHERE product_id = 1;
このSQLを学習しておけば、アプリが使うSQLの形を許可リストに登録できます。今回の検証では、ここに OR 1=1 を足したSQLや、未学習のUPDATEを遮断できました。
通常の権限管理との関係も押さえておきます。
| 仕組み | 今回の例 |
|---|---|
| DBの権限 | 自分が所有する商品テーブルをSELECT・UPDATEできる |
| SQL Firewall | その権限があっても、許可リストにないSQLの実行を制限する |
SQL Firewallで許可したからといって、テーブルへの権限が新しく付与されるわけではありません。今回は先にUPDATEが実行できることを確認し、その後Firewallによって拒否されることを試しています。
制御する対象は2種類
| 対象 | 内容 |
|---|---|
| SQL | 実行してよいSQL文 |
| 接続コンテキスト | 接続元IPアドレス、OSユーザー名、クライアントのプログラム名 |
設定では、SQLだけを見る ENFORCE_SQL、接続条件だけを見る ENFORCE_CONTEXT、両方を見る ENFORCE_ALL を選べます。また、block => FALSE なら違反を記録して処理を続け、TRUE なら遮断します。Oracle公式:設定手順
SQL Firewallを使える条件
SQL Firewallは、クラウドやADBだけの機能ではありません。 Oracle Database自体に組み込まれており、対応するバージョン・エディション・ライセンスがあれば、オンプレミスのデータベースでも利用できます。Oracle公式ガイドでは、オンプレミスとクラウドに加えて、Data GuardやRACの構成でも利用できると説明されています。Oracle公式:対応する配置環境
利用前には、次の条件を確認します。
| 確認項目 | 条件・考え方 |
|---|---|
| DBバージョン | Oracle Database 23aiで追加された機能で、Oracle AI Database 26aiでも利用可能です。19c・21cのDB内蔵機能としては利用できません |
| 配置場所 | ADBに限定されず、オンプレミスの対応DBでも利用できます。ただし、配置場所だけで利用可否が決まるわけではなく、下記の提供形態・ライセンス条件も確認します |
| エディション・ライセンス | Enterprise Editionでは、Oracle Database Vaultオプション、またはOracle Audit Vault and Database Firewallに含まれるSQL Firewallの利用権が必要です。「Enterprise Editionなら追加条件なしで使える」という意味ではありません |
| 管理権限 | 設定を行うユーザーに SQL_FIREWALL_ADMIN ロールが必要です。保護されるアプリ用ユーザーへこの管理ロールを付与する必要はありません |
| 有効化と学習 | 機能を有効化したうえで、対象ユーザーの通常SQLを学習し、許可リストを生成・有効化します。対応DBを用意しただけで自動的に遮断が始まるわけではありません |
23aiでの機能追加はOracle Database 23ai新機能ガイド、管理権限はSQL Firewallの権限ガイドを参照してください。
提供形態ごとの目安は次のとおりです。2026年10月23日時点の公式資料に基づきます。
| 提供形態 | SQL Firewallの利用可否・条件 |
|---|---|
| Oracle AI Database Free | 利用可能。公式の機能表では Y とされています。Freeの利用条件とリソース制限に従います |
| オンプレミスのEnterprise Edition | 利用可能。ただし、上記のDatabase VaultまたはAudit Vault and Database Firewallによる利用権が必要です |
| Standard Edition 2 | 対象外。公式の機能表では N とされています |
| OCI Base Database Service | Standard Editionおよび通常のEnterprise Editionは対象外。Enterprise Edition High Performance / Extreme Performanceは利用可能です |
| OCI Exadata Database Service | 公式の機能表では利用可能です |
| Autonomous AI Database | 対応する26ai環境で利用できます。この記事では、このADB環境で実測しています |
エディション・サービス別の条件はOracle公式のライセンス情報(Security表)、ADBでの提供はセキュリティ機能の概要で確認できます。ライセンス表のSQL Firewall行には、クラウドについて Only available in OCI という注記もあるため、「任意のクラウド上のOracle DBで同じ条件で使える」とは解釈しないでください。
また、ここで扱うDB内蔵の SQL Firewall と、別製品の Oracle Audit Vault and Database Firewall は区別します。後者を導入する場合の対応DBバージョンや構成条件は、この記事のDB内蔵SQL Firewallの条件とは別です。
2. 今回の環境と検証計画
| 項目 | 実測・構成 |
|---|---|
| データベース | Autonomous AI Database / Oracle AI Database 26ai |
| DBが返したバージョン | 23.26.4.1.0 |
| 実行場所 | 作業用Linuxサーバー |
| Python | 3.9.25 |
| 接続ドライバー | python-oracledb 3.4.1、Thinモード |
| DB接続 | ウォレットを使うmTLS接続 |
| 管理操作 |
ADMIN。SQL_FIREWALL_ADMIN ロール保有を確認 |
| 保護対象 | SQLFW_LAB_20261023 |
| 比較対象 | SQLFW_CONTROL_20261023 |
| データ | 各専用スキーマに商品2行 |
製品名は26aiですが、今回のDBが返す内部バージョン文字列は 23.26.4.1.0 でした。
管理操作とアプリのSQLを分けることが、この検証のポイントです。
検証は次の順で進めました。
- DBバージョン・管理ロール・既存設定を確認する。
- 専用ユーザー2名と架空データを作る。
- 通常のSELECTを学習し、許可リストを生成する。
- 監視モードで未学習SQLと違反ログを確認する。
- 遮断モードでSQLの形・条件値・バインド変数を比較する。
- 正規SQLを追加学習し、許可リストを更新する。
- 接続条件を変更し、既存接続と新規接続を比較する。
- 専用ポリシーを停止し、ユーザーをロックして元の設定へ戻す。
既存システムのスキーマにはDDL・DML・権限変更を行っていません。専用ユーザーには CREATE SESSION と CREATE TABLE だけを付与し、各自のテーブルを使います。
3. コマンドの実行方法
作業用サーバーで実行した環境準備コマンドは次のとおりです。
umask 077
python3 -m venv /tmp/sqlfw-lab-20261023
/tmp/sqlfw-lab-20261023/bin/python -m pip --disable-pip-version-check install --quiet oracledb==3.4.1
/tmp/sqlfw-lab-20261023/bin/python -c "import oracledb; print(oracledb.__version__)"
結果:
3.4.1
DB操作はPythonからSQL・PL/SQLを実行しました。実際のリモート実行コマンドは次の形です。プログラムと秘密の接続設定をSSHの標準入力で渡しています。
/tmp/sqlfw-lab-20261023/bin/python -u -
ウォレットはアクセス権を制限した一時ディレクトリに配置し、処理終了時に削除しました。パスワードをコマンドの引数へ書き込む方法は使っていません。
以下のSQLは、このPython処理で実行したものを読みやすく改行しています。SQL*Plusの画面を再現したものではありません。DDL・PL/SQLの「成功」はドライバーが例外なしで完了したこと、SELECTの表は実際の取得行、エラー番号はドライバーが返したOracleエラー番号を示します。
4. 事前確認と専用ユーザーの準備
開始前の状態
管理接続で実行:
SELECT banner_full FROM v$version;
SELECT role FROM session_roles
WHERE role = 'SQL_FIREWALL_ADMIN';
SELECT status, exclude_jobs FROM dba_sql_firewall_status;
SELECT COUNT(*) FROM dba_sql_firewall_allow_lists;
SELECT COUNT(*) FROM dba_sql_firewall_captures;
SELECT COUNT(*) FROM dba_users
WHERE username IN ('SQLFW_LAB_20261023', 'SQLFW_CONTROL_20261023');
結果:
Oracle AI Database 26ai Enterprise Edition Release 23.26.4.1.0 - Production
Version 23.26.4.1.0
ROLE : SQL_FIREWALL_ADMIN
STATUS : DISABLED
EXCLUDE_JOBS : Y
既存の許可リスト数 : 0
既存のキャプチャ数 : 0
専用ユーザーの重複数: 0
EXCLUDE_JOBS=Y はOracle Schedulerのジョブを対象外とする設定です。今回は変更していません。
全体設定が無効で既存のキャプチャ・許可リストが0件であることを確認してから、有効化しました。
BEGIN DBMS_SQL_FIREWALL.ENABLE; END;
結果:成功。
これはDB全体の機能を有効にする操作です。各ユーザーを保護するには、そのユーザーの許可リストを別途有効化します。
ユーザーと商品テーブルを作る
管理接続で実行:
CREATE USER SQLFW_LAB_20261023
IDENTIFIED BY "<GENERATED_PASSWORD>" QUOTA 5M ON DATA;
GRANT CREATE SESSION, CREATE TABLE TO SQLFW_LAB_20261023;
CREATE USER SQLFW_CONTROL_20261023
IDENTIFIED BY "<GENERATED_PASSWORD>" QUOTA 5M ON DATA;
GRANT CREATE SESSION, CREATE TABLE TO SQLFW_CONTROL_20261023;
結果:4文とも成功。パスワードは実行時にそれぞれ生成した値です。
次のSQLを、検証ユーザーと比較ユーザーの両方の接続で実行しました。
CREATE TABLE products (
product_id NUMBER PRIMARY KEY,
product_name VARCHAR2(30),
price NUMBER
);
INSERT INTO products VALUES (1, 'Notebook', 300);
INSERT INTO products VALUES (2, 'Pen', 100);
COMMIT;
結果:テーブル作成成功、各INSERTは1行、COMMIT成功。それぞれのスキーマに独立した同名テーブルができます。
Firewall適用前には実行できることを確かめる
検証ユーザーで実行:
SELECT product_id, product_name, price
FROM products ORDER BY product_id;
| PRODUCT_ID | PRODUCT_NAME | PRICE |
|---|---|---|
| 1 | Notebook | 300 |
| 2 | Pen | 100 |
SELECT product_id, product_name
FROM products WHERE product_id = 1 OR 1=1;
結果:Notebook、Penの2行を取得。
UPDATE products SET price = 1 WHERE product_id = 1;
ROLLBACK;
結果:UPDATEは1行更新、ROLLBACK成功。価格の変更は取り消しました。
5. 通常のSQLを学習する
管理接続でキャプチャを開始します。
BEGIN
DBMS_SQL_FIREWALL.CREATE_CAPTURE(
username => 'SQLFW_LAB_20261023',
top_level_only => TRUE,
start_capture => TRUE
);
END;
結果:成功。
top_level_only => TRUE としたため、今回はクライアントが直接発行するSQLを対象にします。PL/SQL内部のSQLまで含める検証は行っていません。
検証ユーザーで、通常の検索SQLを1つ実行します。
SELECT product_id, product_name
FROM products WHERE product_id = 1;
| PRODUCT_ID | PRODUCT_NAME |
|---|---|
| 1 | Notebook |
管理接続で停止し、取得結果を確認します。
BEGIN DBMS_SQL_FIREWALL.STOP_CAPTURE('SQLFW_LAB_20261023'); END;
SELECT sql_text FROM dba_sql_firewall_capture_logs
WHERE username = 'SQLFW_LAB_20261023'
ORDER BY sql_text;
結果:停止成功。取得したSQLは1種類でした。
SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:"SYS_B_0"
実行時の 1 が :"SYS_B_0" に置き換わっています。SQLはそのままの文字列で保存されるのではなく、リテラル値などを正規化して記録されます。Oracle公式:SQL Firewallの開始と動作
学習させるのは、アプリが正規に実行するSQLです。攻撃を模したSQLまで学習期間に実行すると、それを許可するリストになってしまいます。
6. 許可リストを生成する
管理接続で実行:
BEGIN DBMS_SQL_FIREWALL.GENERATE_ALLOW_LIST('SQLFW_LAB_20261023'); END;
SELECT sql_text FROM dba_sql_firewall_allowed_sql
WHERE username = 'SQLFW_LAB_20261023'
ORDER BY sql_text;
結果:生成成功。許可SQLは次の1種類です。
SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:"SYS_B_0"
接続条件も学習されています。今回は個別の値を出力せず、登録件数だけ確認しました。
SELECT
(SELECT COUNT(*) FROM dba_sql_firewall_allowed_ip_addr
WHERE username='SQLFW_LAB_20261023') AS ip_count,
(SELECT COUNT(*) FROM dba_sql_firewall_allowed_os_user
WHERE username='SQLFW_LAB_20261023') AS os_user_count,
(SELECT COUNT(*) FROM dba_sql_firewall_allowed_os_prog
WHERE username='SQLFW_LAB_20261023') AS program_count
FROM dual;
| IP_COUNT | OS_USER_COUNT | PROGRAM_COUNT |
|---|---|---|
| 1 | 1 | 1 |
7. まずは監視だけにする
管理接続で実行:
BEGIN
DBMS_SQL_FIREWALL.ENABLE_ALLOW_LIST(
username => 'SQLFW_LAB_20261023',
enforce => DBMS_SQL_FIREWALL.ENFORCE_SQL,
block => FALSE
);
END;
結果:成功。
検証ユーザーで、学習していない価格列付きのSQLを実行しました。
SELECT product_id, product_name, price
FROM products ORDER BY product_id;
結果:2行を取得できました。価格も300、100のままです。監視モードなので、未許可のSQLでも実行を継続します。
ログがすぐ見えない場合はFLUSH_LOGS
最初はSQL実行の2秒後に違反ログを参照しましたが、0行でした。後の参照では Allowed / SQL violation の記録を取得できました。
追加検証では、次を実行してからログを確認しました。
BEGIN DBMS_SQL_FIREWALL.FLUSH_LOGS; END;
SELECT sql_text, firewall_action, cause
FROM dba_sql_firewall_violations
WHERE username = 'SQLFW_LAB_20261023'
ORDER BY occurred_at;
このプロシージャは、メモリー中のログをログ表へ反映します。操作直後のログ確認に使えることが公式に説明されています。Oracle公式:FLUSH_LOGS
追加検証では、監視モードで次の未学習SQLも実行しました。
SELECT COUNT(*) FROM products;
結果は 2。フラッシュ後、次の記録が増えました。
| SQL_TEXT | FIREWALL_ACTION | CAUSE |
|---|---|---|
SELECT COUNT (*) FROM PRODUCTS |
Allowed | SQL violation |
SQLが成功したことと、許可リストに一致したことは別です。 監視モードでは、違反ログも確認する必要があります。
8. 未許可のSQLを遮断する
管理接続で、監視用の許可リストをいったん無効化してから遮断モードで有効化しました。
BEGIN DBMS_SQL_FIREWALL.DISABLE_ALLOW_LIST('SQLFW_LAB_20261023'); END;
BEGIN
DBMS_SQL_FIREWALL.ENABLE_ALLOW_LIST(
username => 'SQLFW_LAB_20261023',
enforce => DBMS_SQL_FIREWALL.ENFORCE_SQL,
block => TRUE
);
END;
結果:両方成功。
学習済みSQLと、リテラル値だけの変更
SELECT product_id, product_name FROM products WHERE product_id = 1;
SELECT product_id, product_name FROM products WHERE product_id = 2;
| 条件 | 結果 |
|---|---|
product_id = 1 |
1, Notebook の1行 |
product_id = 2 |
2, Pen の1行 |
学習時に実行したのは 1 だけですが、2 に変えても成功しました。今回のSQLでは、条件値の違いは正規化され、同じ許可SQLとして扱われています。
これは行単位のアクセス制御とは異なります。商品1だけを見せたい場合、SQL Firewallの学習だけでは実現できません。
列追加・OR条件追加・UPDATE
検証ユーザーで実行:
SELECT product_id, product_name, price FROM products ORDER BY product_id;
SELECT product_id, product_name
FROM products WHERE product_id = 1 OR 1=1;
UPDATE products SET price = 1 WHERE product_id = 1;
ROLLBACK;
| 操作 | 実測結果 |
|---|---|
| 未学習の価格列付きSELECT | ORA-47605 |
OR 1=1 を足したSELECT |
ORA-47605 |
| 未学習のUPDATE | ORA-47605 |
| ROLLBACK | 成功 |
ORA-47605 はSQL Firewall違反を表すエラーです。今回はWebアプリに攻撃を送ったのではなく、条件改変後のSQLをDBへ直接発行して比較しました。あらゆるSQLインジェクションへの耐性を網羅検証したものではありません。
一方、比較ユーザーでは次の同じ形のSQLが成功しました。
SELECT product_id, product_name, price FROM products ORDER BY product_id;
結果:2行。保護対象ユーザーの許可リストが、比較ユーザーには適用されていないことを確認できました。
9. 正規の機能追加に合わせてSQLを許可する
価格付きの検索が正規の新機能になったと想定し、そのSQLだけを追加学習します。
管理接続:
BEGIN DBMS_SQL_FIREWALL.DISABLE_ALLOW_LIST('SQLFW_LAB_20261023'); END;
BEGIN DBMS_SQL_FIREWALL.START_CAPTURE('SQLFW_LAB_20261023'); END;
検証ユーザー:
SELECT product_id, product_name, price FROM products ORDER BY product_id;
結果:2行取得。
管理接続:
BEGIN DBMS_SQL_FIREWALL.STOP_CAPTURE('SQLFW_LAB_20261023'); END;
BEGIN
DBMS_SQL_FIREWALL.APPEND_ALLOW_LIST(
username => 'SQLFW_LAB_20261023',
source => DBMS_SQL_FIREWALL.CAPTURE_LOG
);
END;
BEGIN
DBMS_SQL_FIREWALL.ENABLE_ALLOW_LIST(
username => 'SQLFW_LAB_20261023',
enforce => DBMS_SQL_FIREWALL.ENFORCE_SQL,
block => TRUE
);
END;
結果:すべて成功。
同じ価格付きSELECTを再実行すると、遮断モードでも2行取得できました。一方、OR 1=1 を足したSQLを再実行すると、引き続き ORA-47605 でした。
今回は CAPTURE_LOG を追加元にしました。違反ログを一括で取り込むと、拒否したかったSQLも許可してしまう可能性があるため、学習するSQLを限定しています。
10. リテラルSQLとバインドSQLは実際のアプリの形で学習する
今回、予想と異なった点です。リテラルSQLを学習しただけでは、次のバインドSQLは許可されませんでした。
実際に実行したPython部分:
cursor.execute(
'SELECT product_id, product_name FROM products WHERE product_id = :id',
id=2
)
結果:ORA-47605。
そこで、遮断を一時停止してキャプチャを再開し、同じバインドSQLを id=1 で正常実行しました。停止後に FLUSH_LOGS、APPEND_ALLOW_LIST(..., source => DBMS_SQL_FIREWALL.CAPTURE_LOG) を実行し、再び遮断モードにしました。
許可リストには、次の3種類が表示されました。
SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:"SYS_B_0"
SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:ID
SELECT PRODUCT_ID,PRODUCT_NAME,PRICE FROM PRODUCTS ORDER BY PRODUCT_ID
再び上記のPythonコードを id=2 で実行すると、今度は 2, Pen を取得できました。その後も、学習していない SELECT COUNT(*) FROM products は ORA-47605 で拒否されました。
この結果から、今回の環境では、リテラルSQLの学習だけで明示的な :id のバインドSQLまで許可されるとは限らないことがわかります。バインド変数の名前やドライバーによる全差異まで試したわけではありません。アプリが実際に使うSQLとドライバーで学習・動作確認するのが確実です。
11. 接続条件を外れた新規接続を遮断する
まず、学習時と同じ接続条件で ENFORCE_ALL / block=TRUE に変更し、通常SELECTが成功することを確認しました。
次に管理接続で、検証ユーザーの許可プログラム名だけを変更しました。
BEGIN
DBMS_SQL_FIREWALL.DELETE_ALLOWED_CONTEXT(
username => 'SQLFW_LAB_20261023',
context_type => DBMS_SQL_FIREWALL.OS_PROGRAM,
value => NULL
);
END;
BEGIN
DBMS_SQL_FIREWALL.ADD_ALLOWED_CONTEXT(
username => 'SQLFW_LAB_20261023',
context_type => DBMS_SQL_FIREWALL.OS_PROGRAM,
value => 'sqlfw-deliberately-unmatched-client'
);
END;
結果:成功。ここでの value => NULL は、指定した検証ユーザーのプログラム名条件をすべて削除する指定です。対象ユーザー自体をNULLにしているわけではありません。
続いて、許可リストを一度無効化し、接続条件だけをチェックするモードにしました。
BEGIN DBMS_SQL_FIREWALL.DISABLE_ALLOW_LIST('SQLFW_LAB_20261023'); END;
BEGIN
DBMS_SQL_FIREWALL.ENABLE_ALLOW_LIST(
username => 'SQLFW_LAB_20261023',
enforce => DBMS_SQL_FIREWALL.ENFORCE_CONTEXT,
block => TRUE
);
END;
結果:成功。
既存接続と新規接続では結果が異なった
| 操作 | 実測結果 |
|---|---|
| 変更前からある接続で通常SELECTを実行 |
1, Notebook を取得 |
| 同じユーザーで新しくDBへ接続 |
ORA-47605 で接続失敗 |
接続試験は、同じ接続ヘルパーで oracledb.connect(...) を再度呼び出して実行しました。実際の接続設定・パスワードは掲載していません。
公式ガイドにも、接続属性はセッション生成時に検査され、許可リスト有効化前からの既存セッションは条件に一致しなくても終了させず、この場合は違反を記録しないと説明されています。Oracle公式:実行時の考慮事項
接続条件の検証では、新しく接続し直すことが大切です。 初回は既存接続だけで試したため遮断されませんでしたが、新規接続で確認すると拒否されました。
最後に、検証ユーザーのプログラム名をワイルドカードで許可しました。
BEGIN
DBMS_SQL_FIREWALL.ADD_ALLOWED_CONTEXT(
username => 'SQLFW_LAB_20261023',
context_type => DBMS_SQL_FIREWALL.OS_PROGRAM,
value => '%'
);
END;
結果:成功。新規接続が成功し、通常SELECTで 1, Notebook を取得できました。% は今回の復旧確認用です。実運用では、許可するプログラム名を必要な範囲に絞ります。
今回は同じサーバーから、許可リスト側のプログラム名条件を意図的に不一致にした検証です。異なる実IPアドレスや異なるOSユーザーからの試験は行っていません。
12. 違反ログで「SQL違反」と「接続条件違反」を確認する
管理接続で FLUSH_LOGS の後、次を実行しました。
SELECT sql_text, firewall_action, cause
FROM dba_sql_firewall_violations
WHERE username = 'SQLFW_LAB_20261023'
ORDER BY occurred_at;
最終取得結果は11行です。次の表は代表的な5行を抜粋しています。
| SQL_TEXT | FIREWALL_ACTION | CAUSE |
|---|---|---|
SELECT COUNT (*) FROM PRODUCTS |
Allowed | SQL violation |
SELECT COUNT (*) FROM PRODUCTS |
Blocked | SQL violation |
SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:ID |
Blocked | SQL violation |
UPDATE PRODUCTS SET PRICE=:"SYS_B_0" WHERE PRODUCT_ID=:"SYS_B_1" |
Blocked | SQL violation |
NULL |
Blocked | Context violation |
接続時に拒否された行では、今回 SQL_TEXT はNULLでした。SQLを実行する前に接続が拒否された記録として区別できます。実測の FIREWALL_ACTION の表記は Allowed / Blocked でした。
13. (おまけ) 後片付けと既存環境の確認
専用ポリシーを停止し、専用ユーザーをロックしました。
BEGIN DBMS_SQL_FIREWALL.DISABLE_ALLOW_LIST('SQLFW_LAB_20261023'); END;
ALTER USER SQLFW_LAB_20261023 ACCOUNT LOCK;
ALTER USER SQLFW_CONTROL_20261023 ACCOUNT LOCK;
結果:成功。比較ユーザーのロックは初回検証の終了時、検証ユーザーの再ロックは追加検証の終了時にも実行しています。
次のSQLで、検証ユーザー以外の設定が追加されていないことを確認しました。
SELECT COUNT(*) FROM dba_sql_firewall_allow_lists
WHERE username <> 'SQLFW_LAB_20261023';
SELECT COUNT(*) FROM dba_sql_firewall_captures
WHERE username <> 'SQLFW_LAB_20261023';
結果:どちらも0件。開始前が無効だったため、全体設定も元に戻しました。
BEGIN DBMS_SQL_FIREWALL.DISABLE; END;
SELECT status, exclude_jobs FROM dba_sql_firewall_status;
SELECT username, account_status FROM dba_users
WHERE username IN ('SQLFW_LAB_20261023', 'SQLFW_CONTROL_20261023')
ORDER BY username;
SELECT username, status FROM dba_sql_firewall_captures
WHERE username = 'SQLFW_LAB_20261023';
SELECT username, status FROM dba_sql_firewall_allow_lists
WHERE username = 'SQLFW_LAB_20261023';
| 確認内容 | 結果 |
|---|---|
| 全体のSTATUS | DISABLED(開始前と同じ) |
| EXCLUDE_JOBS | Y(開始前と同じ) |
| 検証ユーザー | LOCKED |
| 比較ユーザー | LOCKED |
| 専用キャプチャ | DISABLED |
| 専用許可リスト | DISABLED |
DBMS_SQL_FIREWALL.DISABLE は全体に作用します。今回は、開始前が無効、既存設定0件、終了時も他ユーザーの設定0件という条件を確認して実行しました。既存の保護設定がある環境で、そのまま実行してはいけません。
商品価格も管理接続で確認しました。
SELECT product_id, price
FROM SQLFW_LAB_20261023.products ORDER BY product_id;
| PRODUCT_ID | PRICE |
|---|---|
| 1 | 300 |
| 2 | 100 |
確認用に専用テーブル・キャプチャ・許可リスト・ログは残し、ユーザー削除は行っていません。生成パスワードは成果物に保存していないため、再開する場合は管理者によるパスワード再設定が必要です。
作業用サーバーの既存アプリとnginxは検証前後で active でした。検証後、既存アプリの正しいヘルスチェック /healthz がHTTP 200、nginxがHTTP 301を返すことも確認しました。最初に試した /health・/ready・/ はアプリに存在しないURLで、前後とも404でした。これらの確認はサービス状態と応答の確認であり、既存アプリの全業務機能を網羅したテストではありません。
サーバーとADBは開始時に停止していたため、検証用に起動し、終了後に両方を停止状態へ戻しました。
14. 今回わかったこと
| 確認項目 | 実測結果 |
|---|---|
| 正常SQLの学習・許可リスト生成 | 成功 |
| 監視モードの未許可SQL | 実行成功、Allowedの違反ログ |
| 遮断モードの未許可SELECT・UPDATE | ORA-47605 |
| リテラル値だけを1から2へ変更 | 許可 |
| OR条件を追加 | ORA-47605 |
| 未学習の明示的バインドSQL | ORA-47605 |
| 同じバインドSQLを学習後、値を変更 | 許可 |
| 正規SQLを追加学習 | 追加SQLだけ実行可能になることを確認 |
| 比較ユーザーのSQL | 実行可能 |
| 接続条件に不一致の新規接続 | ORA-47605、Context violation |
| 既存セッション | 接続条件の変更後も使用可能 |
| 操作直後の違反ログ | FLUSH_LOGS後に取得確認 |
初回検証では14判定中11件が想定に一致し、3件は「ログがすぐに見える」「リテラル学習でバインドSQLも通る」「既存接続も接続条件違反で止まる」という検証側の想定と異なりました。この結果を消さずに残し、仕様確認と追加検証を行ったところ、追加の14判定はすべて確認できました。
SQL Firewallの導入では、実際のアプリが発行するSQLを十分に学習し、まず監視で不足を見つけ、その後に遮断へ進める流れが役立ちます。今回試していないストアドPL/SQL内部、ジョブ、接続プール、異なるIPからの接続などは、適用するシステムに合わせて別途確認する範囲です。
実行記録と参考資料
末尾の折りたたみ付録に、初回・追加検証の全116回のSQL、バインド値、結果、エラー番号を実行順で掲載しています。同じ内容を付属の sql-firewall/execution-transcript.md にも保存しました。sql-firewall/operations.md は環境操作の記録、sql-firewall/run_verification.py は実行に使った検証プログラムです。記事本文のSQLは説明用に改行しており、逐語的なSQLは実行記録を参照してください。
仕様の判断はOracle公式ドキュメントと今回の実測を根拠にしました。検証の進め方は、次の記事も参考にしています。
- Oracle公式:SQL Firewallについて
- Oracle公式:DBMS_SQL_FIREWALLによる設定
- Oracle公式:実行時の考慮事項
- Oracle公式:管理プロシージャ
- Oracle公式:データディクショナリ・ビュー
- Qiita:Oracle Database 23ai セキュリティ新機能: SQL Firewall
- アシスト:Oracle Database 23ai新機能!DBセキュリティ対策に効果を発揮するSQLファイアウォール!
- DBひとりでできるもん:SQL Firewallを導入してみました
付録:全SQLと実行結果
初回・追加検証の全116回のSQLと結果を表示
検証日:2026-10-23(JST)。初回と追加確認を実行順に掲載する。
SQLは実行文字列を掲載し、CREATE USER・ALTER USERの生成パスワードだけを置換した。接続操作は接続設定を非公開にした呼び出し形を示す。
DDL・PL/SQLは「SUCCESS」が例外なしの完了を示す。rowcount=0はDDLの対象件数や失敗を意味しない。
SELECTは全取得行を掲載。NULLはDBが返したNULL値。SQLの末尾は読みやすさのためセミコロンを補っている。
初回の3件の想定不一致もそのまま残す。ログ反映、明示的バインドSQLの学習、新規接続の検査について追加確認し、記事で説明した。
初回検証
{
"step": "START",
"time_jst": "2026-10-23T09:59:03.529841+09:00",
"client": "python-oracledb",
"python": "3.9.25"
}
VERSION
実行者:ADMIN
SELECT banner_full FROM v$version;
結果:成功。
取得行数:1。
| BANNER_FULL |
|---|
| Oracle AI Database 26ai Enterprise Edition Release 23.26.4.1.0 - Production Version 23.26.4.1.0 |
INITIAL_STATUS
実行者:ADMIN
SELECT status, exclude_jobs FROM dba_sql_firewall_status;
結果:成功。
取得行数:1。
| STATUS | EXCLUDE_JOBS |
|---|---|
| DISABLED | Y |
ROLE
実行者:ADMIN
SELECT role FROM session_roles WHERE role = 'SQL_FIREWALL_ADMIN';
結果:成功。
取得行数:1。
| ROLE |
|---|
| SQL_FIREWALL_ADMIN |
INITIAL_POLICIES
実行者:ADMIN
SELECT COUNT(*) FROM dba_sql_firewall_allow_lists;
結果:成功。
取得行数:1。
| COUNT(*) |
|---|
| 0 |
INITIAL_CAPTURES
実行者:ADMIN
SELECT COUNT(*) FROM dba_sql_firewall_captures;
結果:成功。
取得行数:1。
| COUNT(*) |
|---|
| 0 |
COLLISION
実行者:ADMIN
SELECT COUNT(*) FROM dba_users WHERE username IN ('SQLFW_LAB_20261023','SQLFW_CONTROL_20261023');
結果:成功。
取得行数:1。
| COUNT(*) |
|---|
| 0 |
GLOBAL_ENABLE
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.ENABLE; END;
結果:成功。
ドライバーのrowcount:0。
CREATE_SQLFW_LAB_20261023
実行者:ADMIN
CREATE USER SQLFW_LAB_20261023 IDENTIFIED BY "<GENERATED_PASSWORD>" QUOTA 5M ON DATA;
結果:成功。
ドライバーのrowcount:0。
GRANT_SQLFW_LAB_20261023
実行者:ADMIN
GRANT CREATE SESSION, CREATE TABLE TO SQLFW_LAB_20261023;
結果:成功。
ドライバーのrowcount:0。
TABLE_SQLFW_LAB_20261023
実行者:SQLFW_LAB_20261023
CREATE TABLE products (product_id NUMBER PRIMARY KEY, product_name VARCHAR2(30), price NUMBER);
結果:成功。
ドライバーのrowcount:0。
DATA1_SQLFW_LAB_20261023
実行者:SQLFW_LAB_20261023
INSERT INTO products VALUES (1, 'Notebook', 300);
結果:成功。
ドライバーのrowcount:1。
DATA2_SQLFW_LAB_20261023
実行者:SQLFW_LAB_20261023
INSERT INTO products VALUES (2, 'Pen', 100);
結果:成功。
ドライバーのrowcount:1。
COMMIT_SQLFW_LAB_20261023
実行者:SQLFW_LAB_20261023
COMMIT;
結果:成功。
ドライバーのrowcount:0。
CREATE_SQLFW_CONTROL_20261023
実行者:ADMIN
CREATE USER SQLFW_CONTROL_20261023 IDENTIFIED BY "<GENERATED_PASSWORD>" QUOTA 5M ON DATA;
結果:成功。
ドライバーのrowcount:0。
GRANT_SQLFW_CONTROL_20261023
実行者:ADMIN
GRANT CREATE SESSION, CREATE TABLE TO SQLFW_CONTROL_20261023;
結果:成功。
ドライバーのrowcount:0。
TABLE_SQLFW_CONTROL_20261023
実行者:SQLFW_CONTROL_20261023
CREATE TABLE products (product_id NUMBER PRIMARY KEY, product_name VARCHAR2(30), price NUMBER);
結果:成功。
ドライバーのrowcount:0。
DATA1_SQLFW_CONTROL_20261023
実行者:SQLFW_CONTROL_20261023
INSERT INTO products VALUES (1, 'Notebook', 300);
結果:成功。
ドライバーのrowcount:1。
DATA2_SQLFW_CONTROL_20261023
実行者:SQLFW_CONTROL_20261023
INSERT INTO products VALUES (2, 'Pen', 100);
結果:成功。
ドライバーのrowcount:1。
COMMIT_SQLFW_CONTROL_20261023
実行者:SQLFW_CONTROL_20261023
COMMIT;
結果:成功。
ドライバーのrowcount:0。
BEFORE_UNSEEN
実行者:SQLFW_LAB_20261023
SELECT product_id, product_name, price FROM products ORDER BY product_id;
結果:成功。
取得行数:2。
| PRODUCT_ID | PRODUCT_NAME | PRICE |
|---|---|---|
| 1 | Notebook | 300 |
| 2 | Pen | 100 |
BEFORE_INJECTION
実行者:SQLFW_LAB_20261023
SELECT product_id, product_name FROM products WHERE product_id = 1 OR 1=1;
結果:成功。
取得行数:2。
| PRODUCT_ID | PRODUCT_NAME |
|---|---|
| 1 | Notebook |
| 2 | Pen |
BEFORE_UPDATE
実行者:SQLFW_LAB_20261023
UPDATE products SET price = 1 WHERE product_id = 1;
結果:成功。
ドライバーのrowcount:1。
BEFORE_ROLLBACK
実行者:SQLFW_LAB_20261023
ROLLBACK;
結果:成功。
ドライバーのrowcount:0。
CAPTURE_START
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.CREATE_CAPTURE(username=>'SQLFW_LAB_20261023',top_level_only=>TRUE,start_capture=>TRUE); END;
結果:成功。
ドライバーのrowcount:0。
TRAIN
実行者:SQLFW_LAB_20261023
SELECT product_id, product_name FROM products WHERE product_id = 1;
結果:成功。
取得行数:1。
| PRODUCT_ID | PRODUCT_NAME |
|---|---|
| 1 | Notebook |
判定:PASS — learned query returns one row
CAPTURE_STOP
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.STOP_CAPTURE('SQLFW_LAB_20261023'); END;
結果:成功。
ドライバーのrowcount:0。
CAPTURE_LOG
実行者:ADMIN
SELECT sql_text FROM dba_sql_firewall_capture_logs WHERE username='SQLFW_LAB_20261023' ORDER BY sql_text;
結果:成功。
取得行数:1。
| SQL_TEXT |
|---|
| SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:"SYS_B_0" |
GENERATE
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.GENERATE_ALLOW_LIST('SQLFW_LAB_20261023'); END;
結果:成功。
ドライバーのrowcount:0。
ALLOWED_SQL
実行者:ADMIN
SELECT sql_text FROM dba_sql_firewall_allowed_sql WHERE username='SQLFW_LAB_20261023' ORDER BY sql_text;
結果:成功。
取得行数:1。
| SQL_TEXT |
|---|
| SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:"SYS_B_0" |
CONTEXT_COUNTS
実行者:ADMIN
SELECT (SELECT COUNT(*) FROM dba_sql_firewall_allowed_ip_addr WHERE username='SQLFW_LAB_20261023') AS ip_count, (SELECT COUNT(*) FROM dba_sql_firewall_allowed_os_user WHERE username='SQLFW_LAB_20261023') AS os_user_count, (SELECT COUNT(*) FROM dba_sql_firewall_allowed_os_prog WHERE username='SQLFW_LAB_20261023') AS program_count FROM dual;
結果:成功。
取得行数:1。
| IP_COUNT | OS_USER_COUNT | PROGRAM_COUNT |
|---|---|---|
| 1 | 1 | 1 |
MONITOR_ENABLE
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.ENABLE_ALLOW_LIST(username=>'SQLFW_LAB_20261023', enforce=>DBMS_SQL_FIREWALL.ENFORCE_SQL, block=>FALSE); END;
結果:成功。
ドライバーのrowcount:0。
MONITOR_UNSEEN
実行者:SQLFW_LAB_20261023
SELECT product_id, product_name, price FROM products ORDER BY product_id;
結果:成功。
取得行数:2。
| PRODUCT_ID | PRODUCT_NAME | PRICE |
|---|---|---|
| 1 | Notebook | 300 |
| 2 | Pen | 100 |
判定:PASS — monitor allows unknown SQL
MONITOR_LOG
実行者:ADMIN
SELECT sql_text, firewall_action, cause FROM dba_sql_firewall_violations WHERE username='SQLFW_LAB_20261023' ORDER BY occurred_at;
結果:成功。
取得行数:0。
判定:想定不一致 — monitor logs violation without blocking
BLOCK_ENABLE_DISABLE
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.DISABLE_ALLOW_LIST('SQLFW_LAB_20261023'); END;
結果:成功。
ドライバーのrowcount:0。
BLOCK_ENABLE
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.ENABLE_ALLOW_LIST(username=>'SQLFW_LAB_20261023', enforce=>DBMS_SQL_FIREWALL.ENFORCE_SQL, block=>TRUE); END;
結果:成功。
ドライバーのrowcount:0。
BLOCK_NORMAL
実行者:SQLFW_LAB_20261023
SELECT product_id, product_name FROM products WHERE product_id = 1;
結果:成功。
取得行数:1。
| PRODUCT_ID | PRODUCT_NAME |
|---|---|
| 1 | Notebook |
判定:PASS — learned SQL allowed
BLOCK_LITERAL
実行者:SQLFW_LAB_20261023
SELECT product_id, product_name FROM products WHERE product_id = 2;
結果:成功。
取得行数:1。
| PRODUCT_ID | PRODUCT_NAME |
|---|---|
| 2 | Pen |
判定:PASS — different literal allowed
BLOCK_BIND
実行者:SQLFW_LAB_20261023
SELECT product_id, product_name FROM products WHERE product_id = :id;
バインド値:{"id": 2}。
結果:ORA-47605(SQL Firewall違反)。
判定:想定不一致 — bind value allowed
BLOCK_UNSEEN
実行者:SQLFW_LAB_20261023
SELECT product_id, product_name, price FROM products ORDER BY product_id;
結果:ORA-47605(SQL Firewall違反)。
判定:PASS — BLOCK_UNSEEN
BLOCK_INJECTION
実行者:SQLFW_LAB_20261023
SELECT product_id, product_name FROM products WHERE product_id = 1 OR 1=1;
結果:ORA-47605(SQL Firewall違反)。
判定:PASS — BLOCK_INJECTION
BLOCK_UPDATE
実行者:SQLFW_LAB_20261023
UPDATE products SET price = 1 WHERE product_id = 1;
結果:ORA-47605(SQL Firewall違反)。
判定:PASS — BLOCK_UPDATE
BLOCK_ROLLBACK
実行者:SQLFW_LAB_20261023
ROLLBACK;
結果:成功。
ドライバーのrowcount:0。
CONTROL_UNSEEN
実行者:SQLFW_CONTROL_20261023
SELECT product_id, product_name, price FROM products ORDER BY product_id;
結果:成功。
取得行数:2。
| PRODUCT_ID | PRODUCT_NAME | PRICE |
|---|---|---|
| 1 | Notebook | 300 |
| 2 | Pen | 100 |
判定:PASS — control user unaffected
BLOCK_LOG
実行者:ADMIN
SELECT sql_text, firewall_action, cause FROM dba_sql_firewall_violations WHERE username='SQLFW_LAB_20261023' ORDER BY occurred_at;
結果:成功。
取得行数:0。
CHANGE_DISABLE
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.DISABLE_ALLOW_LIST('SQLFW_LAB_20261023'); END;
結果:成功。
ドライバーのrowcount:0。
RETRAIN_START
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.START_CAPTURE('SQLFW_LAB_20261023'); END;
結果:成功。
ドライバーのrowcount:0。
RETRAIN_APPROVED
実行者:SQLFW_LAB_20261023
SELECT product_id, product_name, price FROM products ORDER BY product_id;
結果:成功。
取得行数:2。
| PRODUCT_ID | PRODUCT_NAME | PRICE |
|---|---|---|
| 1 | Notebook | 300 |
| 2 | Pen | 100 |
RETRAIN_STOP
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.STOP_CAPTURE('SQLFW_LAB_20261023'); END;
結果:成功。
ドライバーのrowcount:0。
APPEND
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.APPEND_ALLOW_LIST(username=>'SQLFW_LAB_20261023',source=>DBMS_SQL_FIREWALL.CAPTURE_LOG); END;
結果:成功。
ドライバーのrowcount:0。
UPDATED_ENABLE
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.ENABLE_ALLOW_LIST(username=>'SQLFW_LAB_20261023', enforce=>DBMS_SQL_FIREWALL.ENFORCE_SQL, block=>TRUE); END;
結果:成功。
ドライバーのrowcount:0。
UPDATED_UNSEEN
実行者:SQLFW_LAB_20261023
SELECT product_id, product_name, price FROM products ORDER BY product_id;
結果:成功。
取得行数:2。
| PRODUCT_ID | PRODUCT_NAME | PRICE |
|---|---|---|
| 1 | Notebook | 300 |
| 2 | Pen | 100 |
判定:PASS — newly approved SQL succeeds
UPDATED_INJECTION
実行者:SQLFW_LAB_20261023
SELECT product_id, product_name FROM products WHERE product_id = 1 OR 1=1;
結果:ORA-47605(SQL Firewall違反)。
判定:PASS — UPDATED_INJECTION
UPDATED_SQL
実行者:ADMIN
SELECT sql_text FROM dba_sql_firewall_allowed_sql WHERE username='SQLFW_LAB_20261023' ORDER BY sql_text;
結果:成功。
取得行数:2。
| SQL_TEXT |
|---|
| SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:"SYS_B_0" |
| SELECT PRODUCT_ID,PRODUCT_NAME,PRICE FROM PRODUCTS ORDER BY PRODUCT_ID |
CONTEXT_CLEAR_PROGRAM
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.DELETE_ALLOWED_CONTEXT(username=>'SQLFW_LAB_20261023', context_type=>DBMS_SQL_FIREWALL.OS_PROGRAM, value=>NULL); END;
結果:成功。
ドライバーのrowcount:0。
CONTEXT_SET_PROGRAM
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.ADD_ALLOWED_CONTEXT(username=>'SQLFW_LAB_20261023', context_type=>DBMS_SQL_FIREWALL.OS_PROGRAM, value=>'sqlfw-deliberately-unmatched-client'); END;
結果:成功。
ドライバーのrowcount:0。
CONTEXT_ENABLE_DISABLE
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.DISABLE_ALLOW_LIST('SQLFW_LAB_20261023'); END;
結果:成功。
ドライバーのrowcount:0。
CONTEXT_ENABLE
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.ENABLE_ALLOW_LIST(username=>'SQLFW_LAB_20261023', enforce=>DBMS_SQL_FIREWALL.ENFORCE_CONTEXT, block=>TRUE); END;
結果:成功。
ドライバーのrowcount:0。
CONTEXT_BLOCK
実行者:SQLFW_LAB_20261023
SELECT product_id, product_name FROM products WHERE product_id = 1;
結果:成功。
取得行数:1。
| PRODUCT_ID | PRODUCT_NAME |
|---|---|
| 1 | Notebook |
判定:想定不一致 — CONTEXT_BLOCK
CONTEXT_ALLOW_ANY_PROGRAM
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.ADD_ALLOWED_CONTEXT(username=>'SQLFW_LAB_20261023', context_type=>DBMS_SQL_FIREWALL.OS_PROGRAM, value=>'%'); END;
結果:成功。
ドライバーのrowcount:0。
CONTEXT_RECOVER
実行者:SQLFW_LAB_20261023
SELECT product_id, product_name FROM products WHERE product_id = 1;
結果:成功。
取得行数:1。
| PRODUCT_ID | PRODUCT_NAME |
|---|---|
| 1 | Notebook |
判定:PASS — context change takes effect immediately
FINAL_VIOLATIONS
実行者:ADMIN
SELECT sql_text, firewall_action, cause FROM dba_sql_firewall_violations WHERE username='SQLFW_LAB_20261023' ORDER BY occurred_at;
結果:成功。
取得行数:5。
| SQL_TEXT | FIREWALL_ACTION | CAUSE |
|---|---|---|
| SELECT PRODUCT_ID,PRODUCT_NAME,PRICE FROM PRODUCTS ORDER BY PRODUCT_ID | Allowed | SQL violation |
| SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:ID | Blocked | SQL violation |
| SELECT PRODUCT_ID,PRODUCT_NAME,PRICE FROM PRODUCTS ORDER BY PRODUCT_ID | Blocked | SQL violation |
| SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:"SYS_B_0" OR :"SYS_B_1"=:"SYS_B_2" | Blocked | SQL violation |
| UPDATE PRODUCTS SET PRICE=:"SYS_B_0" WHERE PRODUCT_ID=:"SYS_B_1" | Blocked | SQL violation |
CLEAN_POLICY_DISABLE
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.DISABLE_ALLOW_LIST('SQLFW_LAB_20261023'); END;
結果:成功。
ドライバーのrowcount:0。
CLEAN_LOCK_SQLFW_LAB_20261023
実行者:ADMIN
ALTER USER SQLFW_LAB_20261023 ACCOUNT LOCK;
結果:成功。
ドライバーのrowcount:0。
CLEAN_LOCK_SQLFW_CONTROL_20261023
実行者:ADMIN
ALTER USER SQLFW_CONTROL_20261023 ACCOUNT LOCK;
結果:成功。
ドライバーのrowcount:0。
FOREIGN_POLICIES
実行者:ADMIN
SELECT COUNT(*) FROM dba_sql_firewall_allow_lists WHERE username<>'SQLFW_LAB_20261023';
結果:成功。
取得行数:1。
| COUNT(*) |
|---|
| 0 |
FOREIGN_CAPTURES
実行者:ADMIN
SELECT COUNT(*) FROM dba_sql_firewall_captures WHERE username<>'SQLFW_LAB_20261023';
結果:成功。
取得行数:1。
| COUNT(*) |
|---|
| 0 |
GLOBAL_RESTORE
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.DISABLE; END;
結果:成功。
ドライバーのrowcount:0。
FINAL_STATUS
実行者:ADMIN
SELECT status, exclude_jobs FROM dba_sql_firewall_status;
結果:成功。
取得行数:1。
| STATUS | EXCLUDE_JOBS |
|---|---|
| DISABLED | Y |
FINAL_USERS
実行者:ADMIN
SELECT username,account_status FROM dba_users WHERE username IN ('SQLFW_LAB_20261023','SQLFW_CONTROL_20261023') ORDER BY username;
結果:成功。
取得行数:2。
| USERNAME | ACCOUNT_STATUS |
|---|---|
| SQLFW_CONTROL_20261023 | LOCKED |
| SQLFW_LAB_20261023 | LOCKED |
FINAL_CAPTURE
実行者:ADMIN
SELECT username,status FROM dba_sql_firewall_captures WHERE username='SQLFW_LAB_20261023';
結果:成功。
取得行数:1。
| USERNAME | STATUS |
|---|---|
| SQLFW_LAB_20261023 | DISABLED |
FINAL_POLICY
実行者:ADMIN
SELECT username,status FROM dba_sql_firewall_allow_lists WHERE username='SQLFW_LAB_20261023';
結果:成功。
取得行数:1。
| USERNAME | STATUS |
|---|---|
| SQLFW_LAB_20261023 | DISABLED |
{
"step": "SUMMARY",
"passed": 11,
"total": 14,
"all_passed": false
}
追加検証
{
"step": "FOLLOWUP_START",
"time_jst": "2026-10-23T10:00:43.464586+09:00"
}
F_INITIAL
実行者:ADMIN
SELECT status,exclude_jobs FROM dba_sql_firewall_status;
結果:成功。
取得行数:1。
| STATUS | EXCLUDE_JOBS |
|---|---|
| DISABLED | Y |
F_FOREIGN
実行者:ADMIN
SELECT (SELECT COUNT(*) FROM dba_sql_firewall_allow_lists WHERE username<>'SQLFW_LAB_20261023'), (SELECT COUNT(*) FROM dba_sql_firewall_captures WHERE username<>'SQLFW_LAB_20261023') FROM dual;
結果:成功。
取得行数:1。
| (SELECTCOUNT(*)FROMDBA_SQL_FIREWALL_ALLOW_LISTSWHEREUSERNAME<>'SQLFW_LAB_20261023') | (SELECTCOUNT(*)FROMDBA_SQL_FIREWALL_CAPTURESWHEREUSERNAME<>'SQLFW_LAB_20261023') |
|---|---|
| 0 | 0 |
F_ENABLE
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.ENABLE; END;
結果:成功。
ドライバーのrowcount:0。
F_UNLOCK
実行者:ADMIN
ALTER USER SQLFW_LAB_20261023 IDENTIFIED BY "<GENERATED_PASSWORD>" ACCOUNT UNLOCK;
結果:成功。
ドライバーのrowcount:0。
F_FLUSH_BASELINE
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.FLUSH_LOGS; END;
結果:成功。
ドライバーのrowcount:0。
F_BASELINE_LOG_FLUSH
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.FLUSH_LOGS; END;
結果:成功。
ドライバーのrowcount:0。
F_BASELINE_LOG
実行者:ADMIN
SELECT sql_text,firewall_action,cause FROM dba_sql_firewall_violations WHERE username='SQLFW_LAB_20261023' ORDER BY occurred_at;
結果:成功。
取得行数:6。
| SQL_TEXT | FIREWALL_ACTION | CAUSE |
|---|---|---|
| SELECT PRODUCT_ID,PRODUCT_NAME,PRICE FROM PRODUCTS ORDER BY PRODUCT_ID | Allowed | SQL violation |
| SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:ID | Blocked | SQL violation |
| SELECT PRODUCT_ID,PRODUCT_NAME,PRICE FROM PRODUCTS ORDER BY PRODUCT_ID | Blocked | SQL violation |
| SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:"SYS_B_0" OR :"SYS_B_1"=:"SYS_B_2" | Blocked | SQL violation |
| UPDATE PRODUCTS SET PRICE=:"SYS_B_0" WHERE PRODUCT_ID=:"SYS_B_1" | Blocked | SQL violation |
| SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:"SYS_B_0" OR :"SYS_B_1"=:"SYS_B_2" | Blocked | SQL violation |
F_MONITOR
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.ENABLE_ALLOW_LIST(username=>'SQLFW_LAB_20261023',enforce=>DBMS_SQL_FIREWALL.ENFORCE_SQL,block=>FALSE); END;
結果:成功。
ドライバーのrowcount:0。
F_MONITOR_SQL
実行者:SQLFW_LAB_20261023
SELECT COUNT(*) FROM products;
結果:成功。
取得行数:1。
| COUNT(*) |
|---|
| 2 |
判定:PASS — monitor unknown aggregate returns two
F_MONITOR_LOG_FLUSH
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.FLUSH_LOGS; END;
結果:成功。
ドライバーのrowcount:0。
F_MONITOR_LOG
実行者:ADMIN
SELECT sql_text,firewall_action,cause FROM dba_sql_firewall_violations WHERE username='SQLFW_LAB_20261023' ORDER BY occurred_at;
結果:成功。
取得行数:7。
| SQL_TEXT | FIREWALL_ACTION | CAUSE |
|---|---|---|
| SELECT PRODUCT_ID,PRODUCT_NAME,PRICE FROM PRODUCTS ORDER BY PRODUCT_ID | Allowed | SQL violation |
| SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:ID | Blocked | SQL violation |
| SELECT PRODUCT_ID,PRODUCT_NAME,PRICE FROM PRODUCTS ORDER BY PRODUCT_ID | Blocked | SQL violation |
| SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:"SYS_B_0" OR :"SYS_B_1"=:"SYS_B_2" | Blocked | SQL violation |
| UPDATE PRODUCTS SET PRICE=:"SYS_B_0" WHERE PRODUCT_ID=:"SYS_B_1" | Blocked | SQL violation |
| SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:"SYS_B_0" OR :"SYS_B_1"=:"SYS_B_2" | Blocked | SQL violation |
| SELECT COUNT (*) FROM PRODUCTS | Allowed | SQL violation |
判定:PASS — flushed monitor log increases Allowed count
F_BLOCK_DISABLE
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.DISABLE_ALLOW_LIST('SQLFW_LAB_20261023'); END;
結果:成功。
ドライバーのrowcount:0。
F_BLOCK
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.ENABLE_ALLOW_LIST(username=>'SQLFW_LAB_20261023',enforce=>DBMS_SQL_FIREWALL.ENFORCE_SQL,block=>TRUE); END;
結果:成功。
ドライバーのrowcount:0。
F_BLOCK_AGGREGATE
実行者:SQLFW_LAB_20261023
SELECT COUNT(*) FROM products;
結果:ORA-47605(SQL Firewall違反)。
判定:PASS — F_BLOCK_AGGREGATE
F_BIND_BEFORE_TRAIN
実行者:SQLFW_LAB_20261023
SELECT product_id, product_name FROM products WHERE product_id = :id;
バインド値:{"id": 1}。
結果:ORA-47605(SQL Firewall違反)。
判定:PASS — F_BIND_BEFORE_TRAIN
F_TRAIN_DISABLE
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.DISABLE_ALLOW_LIST('SQLFW_LAB_20261023'); END;
結果:成功。
ドライバーのrowcount:0。
F_TRAIN_START
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.START_CAPTURE('SQLFW_LAB_20261023'); END;
結果:成功。
ドライバーのrowcount:0。
F_TRAIN_BIND
実行者:SQLFW_LAB_20261023
SELECT product_id, product_name FROM products WHERE product_id = :id;
バインド値:{"id": 1}。
結果:成功。
取得行数:1。
| COLUMN_1 | COLUMN_2 |
|---|---|
| 1 | Notebook |
判定:PASS — F_TRAIN_BIND
F_TRAIN_STOP
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.STOP_CAPTURE('SQLFW_LAB_20261023'); END;
結果:成功。
ドライバーのrowcount:0。
F_TRAIN_FLUSH
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.FLUSH_LOGS; END;
結果:成功。
ドライバーのrowcount:0。
F_APPEND
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.APPEND_ALLOW_LIST(username=>'SQLFW_LAB_20261023',source=>DBMS_SQL_FIREWALL.CAPTURE_LOG); END;
結果:成功。
ドライバーのrowcount:0。
F_ALLOWED
実行者:ADMIN
SELECT sql_text FROM dba_sql_firewall_allowed_sql WHERE username='SQLFW_LAB_20261023' ORDER BY sql_text;
結果:成功。
取得行数:3。
| SQL_TEXT |
|---|
| SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:"SYS_B_0" |
| SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:ID |
| SELECT PRODUCT_ID,PRODUCT_NAME,PRICE FROM PRODUCTS ORDER BY PRODUCT_ID |
F_REENABLE
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.ENABLE_ALLOW_LIST(username=>'SQLFW_LAB_20261023',enforce=>DBMS_SQL_FIREWALL.ENFORCE_SQL,block=>TRUE); END;
結果:成功。
ドライバーのrowcount:0。
F_BIND_AFTER_TRAIN
実行者:SQLFW_LAB_20261023
SELECT product_id, product_name FROM products WHERE product_id = :id;
バインド値:{"id": 2}。
結果:成功。
取得行数:1。
| COLUMN_1 | COLUMN_2 |
|---|---|
| 2 | Pen |
判定:PASS — F_BIND_AFTER_TRAIN
F_STILL_BLOCK_AGGREGATE
実行者:SQLFW_LAB_20261023
SELECT COUNT(*) FROM products;
結果:ORA-47605(SQL Firewall違反)。
判定:PASS — F_STILL_BLOCK_AGGREGATE
F_ALL_ENABLE_DISABLE
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.DISABLE_ALLOW_LIST('SQLFW_LAB_20261023'); END;
結果:成功。
ドライバーのrowcount:0。
F_ALL_ENABLE
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.ENABLE_ALLOW_LIST(username=>'SQLFW_LAB_20261023',enforce=>DBMS_SQL_FIREWALL.ENFORCE_ALL,block=>TRUE); END;
結果:成功。
ドライバーのrowcount:0。
F_ALL_NORMAL
実行者:SQLFW_LAB_20261023
SELECT product_id, product_name FROM products WHERE product_id = 1;
結果:成功。
取得行数:1。
| PRODUCT_ID | PRODUCT_NAME |
|---|---|
| 1 | Notebook |
判定:PASS — combined mode accepts trusted context and SQL
F_PROGRAM_CLEAR
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.DELETE_ALLOWED_CONTEXT(username=>'SQLFW_LAB_20261023',context_type=>DBMS_SQL_FIREWALL.OS_PROGRAM,value=>NULL); END;
結果:成功。
ドライバーのrowcount:0。
F_PROGRAM_RESTRICT
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.ADD_ALLOWED_CONTEXT(username=>'SQLFW_LAB_20261023',context_type=>DBMS_SQL_FIREWALL.OS_PROGRAM,value=>'sqlfw-deliberately-unmatched-client'); END;
結果:成功。
ドライバーのrowcount:0。
F_CONTEXT_DISABLE
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.DISABLE_ALLOW_LIST('SQLFW_LAB_20261023'); END;
結果:成功。
ドライバーのrowcount:0。
F_CONTEXT
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.ENABLE_ALLOW_LIST(username=>'SQLFW_LAB_20261023',enforce=>DBMS_SQL_FIREWALL.ENFORCE_CONTEXT,block=>TRUE); END;
結果:成功。
ドライバーのrowcount:0。
F_EXISTING_SESSION
実行者:SQLFW_LAB_20261023
SELECT product_id, product_name FROM products WHERE product_id = 1;
結果:成功。
取得行数:1。
| PRODUCT_ID | PRODUCT_NAME |
|---|---|
| 1 | Notebook |
判定:PASS — preexisting session remains usable
F_NEW_CONNECTION_BLOCK
実行者:SQLFW_LAB_20261023
oracledb.connect(user=LAB, password=<GENERATED_PASSWORD>, **private_connection_settings)
結果:ORA-47605(SQL Firewall違反)。
判定:PASS — new connection rejected by context
F_PROGRAM_ALLOW
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.ADD_ALLOWED_CONTEXT(username=>'SQLFW_LAB_20261023',context_type=>DBMS_SQL_FIREWALL.OS_PROGRAM,value=>'%'); END;
結果:成功。
ドライバーのrowcount:0。
F_NEW_CONNECTION_RECOVER
実行者:SQLFW_LAB_20261023
oracledb.connect(user=LAB, password=<GENERATED_PASSWORD>, **private_connection_settings)
結果:成功。
F_FRESH_SQL
実行者:SQLFW_LAB_20261023
SELECT product_id, product_name FROM products WHERE product_id = 1;
結果:成功。
取得行数:1。
| PRODUCT_ID | PRODUCT_NAME |
|---|---|
| 1 | Notebook |
判定:PASS — fresh connection recovers
F_FINAL_LOG_FLUSH
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.FLUSH_LOGS; END;
結果:成功。
ドライバーのrowcount:0。
F_FINAL_LOG
実行者:ADMIN
SELECT sql_text,firewall_action,cause FROM dba_sql_firewall_violations WHERE username='SQLFW_LAB_20261023' ORDER BY occurred_at;
結果:成功。
取得行数:11。
| SQL_TEXT | FIREWALL_ACTION | CAUSE |
|---|---|---|
| SELECT PRODUCT_ID,PRODUCT_NAME,PRICE FROM PRODUCTS ORDER BY PRODUCT_ID | Allowed | SQL violation |
| SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:ID | Blocked | SQL violation |
| SELECT PRODUCT_ID,PRODUCT_NAME,PRICE FROM PRODUCTS ORDER BY PRODUCT_ID | Blocked | SQL violation |
| SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:"SYS_B_0" OR :"SYS_B_1"=:"SYS_B_2" | Blocked | SQL violation |
| UPDATE PRODUCTS SET PRICE=:"SYS_B_0" WHERE PRODUCT_ID=:"SYS_B_1" | Blocked | SQL violation |
| SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:"SYS_B_0" OR :"SYS_B_1"=:"SYS_B_2" | Blocked | SQL violation |
| SELECT COUNT (*) FROM PRODUCTS | Allowed | SQL violation |
| SELECT COUNT (*) FROM PRODUCTS | Blocked | SQL violation |
| SELECT PRODUCT_ID,PRODUCT_NAME FROM PRODUCTS WHERE PRODUCT_ID=:ID | Blocked | SQL violation |
| SELECT COUNT (*) FROM PRODUCTS | Blocked | SQL violation |
| NULL | Blocked | Context violation |
判定:PASS — context violation is logged
判定:PASS — monitor and blocked SQL are logged
F_DATA_INTEGRITY
実行者:ADMIN
SELECT product_id,price FROM SQLFW_LAB_20261023.products ORDER BY product_id;
結果:成功。
取得行数:2。
| PRODUCT_ID | PRICE |
|---|---|
| 1 | 300 |
| 2 | 100 |
判定:PASS — product prices unchanged
F_POLICY_DISABLE
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.DISABLE_ALLOW_LIST('SQLFW_LAB_20261023'); END;
結果:成功。
ドライバーのrowcount:0。
F_LOCK
実行者:ADMIN
ALTER USER SQLFW_LAB_20261023 ACCOUNT LOCK;
結果:成功。
ドライバーのrowcount:0。
F_FINAL_FOREIGN
実行者:ADMIN
SELECT (SELECT COUNT(*) FROM dba_sql_firewall_allow_lists WHERE username<>'SQLFW_LAB_20261023'), (SELECT COUNT(*) FROM dba_sql_firewall_captures WHERE username<>'SQLFW_LAB_20261023') FROM dual;
結果:成功。
取得行数:1。
| (SELECTCOUNT(*)FROMDBA_SQL_FIREWALL_ALLOW_LISTSWHEREUSERNAME<>'SQLFW_LAB_20261023') | (SELECTCOUNT(*)FROMDBA_SQL_FIREWALL_CAPTURESWHEREUSERNAME<>'SQLFW_LAB_20261023') |
|---|---|
| 0 | 0 |
F_GLOBAL_RESTORE
実行者:ADMIN
BEGIN DBMS_SQL_FIREWALL.DISABLE; END;
結果:成功。
ドライバーのrowcount:0。
F_FINAL_STATUS
実行者:ADMIN
SELECT status,exclude_jobs FROM dba_sql_firewall_status;
結果:成功。
取得行数:1。
| STATUS | EXCLUDE_JOBS |
|---|---|
| DISABLED | Y |
F_FINAL_USERS
実行者:ADMIN
SELECT username,account_status FROM dba_users WHERE username IN ('SQLFW_LAB_20261023','SQLFW_CONTROL_20261023') ORDER BY username;
結果:成功。
取得行数:2。
| USERNAME | ACCOUNT_STATUS |
|---|---|
| SQLFW_CONTROL_20261023 | LOCKED |
| SQLFW_LAB_20261023 | LOCKED |
F_FINAL_POLICY
実行者:ADMIN
SELECT username,status,enforce,block FROM dba_sql_firewall_allow_lists WHERE username='SQLFW_LAB_20261023';
結果:成功。
取得行数:1。
| USERNAME | STATUS | ENFORCE | BLOCK |
|---|---|---|---|
| SQLFW_LAB_20261023 | DISABLED | ENFORCE_CONTEXT | Y |
{
"step": "FOLLOWUP_SUMMARY",
"passed": 14,
"total": 14,
"all_passed": true
}