🏁 はじめに
前回の記事「Select AI × VPDで実現するセキュアな自然言語アクセス」では、部門ごとの行レベル制御をVPD(Virtual Private Database)で実現する方法を紹介しました。
今回はその続編として、列の中身(値)を動的にマスクする Data Redaction にフォーカスします。
Oracle Database 23ai の Select AI 機能と組み合わせることで、
自然言語での問い合わせでも個人情報をDB側で安全に保護する方法を解説します。
Data Redactionとは❓️
アプリケーションやSQLクエリの修正を行わずに、データベース側で値を自動的にマスク(隠蔽) する機能です。
たとえば、社員テーブルの電話番号カラムに対して、
「人事部以外のユーザーは電話番号を見せない」というルールを定義しておくと、
SELECT文の結果が自動的にマスクされます。
select ai 社員の電話番号教えて;
-- 結果
| 社員名 | 電話番号 |
|-----------|----------------|
| 佐藤 花子 | ***-****-**** |
| 高橋 大輔 | ***-****-**** |
特徴としては以下の点が挙げられます。
✅ SQLやアプリ側の修正が不要
アプリが通常通りSelect文を実行しても、DBが自動でマスク結果を返す。
✅ 実データはそのまま保持される
物理データは変更されず、セッション/ユーザーごとに論理的にマスキング。
✅ 柔軟なマスキングルール指定が可能
正規表現・ランダム文字・部分マスクなど多様な function_type により制御。
つまり、Data Redactionは「見せない」というよりはむしろ「見せ方を変える」制御です。
同じテーブルに対しても、ユーザー属性(SYS_CONTEXT)やアプリコンテキストに応じて
動的に出力を変更できる点が非常に強力です。
Data Redactionの各パターン
🔖 function_type 一覧表はこちら⬇️
| function_type no. | function_type | マスキング内容 | 出力例 (090-1234-5678) |
主な用途 |
|---|---|---|---|---|
| 0 | DBMS_REDACT.NONE |
変更なし(マスキング無効) | 090-1234-5678 |
テスト・確認用 |
| 1 | DBMS_REDACT.FULL |
全桁に空文字指定 | `` | 完全非表示 |
| 2 | DBMS_REDACT.PARTIAL |
一部だけマスク(入力/出力フォーマット指定) | 090-XXXX-XXXX |
先頭のみ見せる、電話番号・カード番号など |
| 4 | DBMS_REDACT.RANDOM |
乱数/英数記号などのランダム文字に置換(毎回異なる) |
e:3(NhmhB;0
|
本番データを見せずに形式だけ維持したいとき |
| 5 | DBMS_REDACT.REGEXP |
正規表現にマッチした数字を任意文字(例: *)に置換 |
***-****-**** |
柔軟に文字列パターンを処理したい場合 |
| 7 | DBMS_REDACT.REGEXP_WIDTH |
REGEXP と同様だが列の文字幅を保持 | ***-****-**** |
OCI/OLE DB 経由アプリとの互換性維持 |
| 6 | DBMS_REDACT.NULLIFY |
値を NULL として返却 | (NULL) | 空欄扱いにしたい場合(非表示化) |
Data Redactionポリシー指定方法
GRANT EXECUTE ON DBMS_REDACT TO SELECT_AI_USER;
アプリケーションコンテキストを適宜、既存認証機構に合わせて設定します。
参考
-- 開発部のユーザ
BEGIN
select_ai_user.pkg_emp_ctx.set_dept('開発部');
END;
Data Redactionのマスキングタイプごとの設定方法は下記です:
1️⃣ NONE(マスクなし)
BEGIN
DBMS_REDACT.ADD_POLICY(
object_schema => 'SELECT_AI_USER',
object_name => 'EMPLOYEE_PRIVATE',
policy_name => 'REDACT_PHONE',
column_name => 'PHONE',
function_type => DBMS_REDACT.NONE,
expression => 'SYS_CONTEXT(''EMP_CTX'',''DEPT'') <> ''人事部'''
);
END;
/
2️⃣ FULL(完全マスク)
BEGIN
DBMS_REDACT.ADD_POLICY(
object_schema => 'SELECT_AI_USER',
object_name => 'EMPLOYEE_PRIVATE',
policy_name => 'REDACT_PHONE',
column_name => 'PHONE',
function_type => DBMS_REDACT.FULL,
expression => 'SYS_CONTEXT(''EMP_CTX'',''DEPT'') <> ''人事部'''
);
END;
/
3️⃣ PARTIAL(部分マスク)
BEGIN
DBMS_REDACT.ADD_POLICY(
object_schema => 'SELECT_AI_USER',
object_name => 'EMPLOYEE_PRIVATE',
policy_name => 'REDACT_PHONE',
column_name => 'PHONE',
function_type => DBMS_REDACT.PARTIAL,
function_parameters => 'VVVFVVVVFVVVV,VVV-VVVV-VVVV,X,4,11',
expression => 'SYS_CONTEXT(''EMP_CTX'',''DEPT'') <> ''人事部'''
);
END;
/
4️⃣ RANDOM(ランダム値に置換)
BEGIN
DBMS_REDACT.ADD_POLICY(
object_schema => 'SELECT_AI_USER',
object_name => 'EMPLOYEE_PRIVATE',
policy_name => 'REDACT_PHONE',
column_name => 'PHONE',
function_type => DBMS_REDACT.RANDOM,
expression => 'SYS_CONTEXT(''EMP_CTX'',''DEPT'') <> ''人事部'''
);
END;
/
5️⃣ REGEXP(正規表現マスク)
BEGIN
DBMS_REDACT.ADD_POLICY(
object_schema => 'SELECT_AI_USER',
object_name => 'EMPLOYEE_PRIVATE',
policy_name => 'REDACT_PHONE',
column_name => 'PHONE',
function_type => DBMS_REDACT.REGEXP,
regexp_pattern => '[0-9]',
regexp_replace_string => '*',
expression => 'SYS_CONTEXT(''EMP_CTX'',''DEPT'') <> ''人事部'''
);
END;
/
6️⃣ REGEXP_WIDTH(正規表現+文字幅維持)
REGEXPと指定方法は同じなため省略
7️⃣ NULLFY(NULL)
BEGIN
DBMS_REDACT.ADD_POLICY(
object_schema => 'SELECT_AI_USER',
object_name => 'EMPLOYEE_PRIVATE',
policy_name => 'REDACT_PHONE',
column_name => 'PHONE',
function_type => DBMS_REDACT.NULLIFY,
expression => 'SYS_CONTEXT(''EMP_CTX'',''DEPT'') <> ''人事部'''
);
END;
/
Data Redactionポリシー確認&削除
SELECT * FROM REDACTION_POLICIES;
BEGIN
DBMS_REDACT.DROP_POLICY(
object_schema => 'SELECT_AI_USER',
object_name => 'EMPLOYEE_PRIVATE',
policy_name => 'REDACT_PHONE'
);
END;
/
🤖 Select AI × Data Redaction
Select AI と Data Redaction を組み合わせることで、
自然言語からの問い合わせに対しても 安全に個人情報をマスキング した結果を返すことができます。
たとえば、以下のように「社員の電話番号を教えて」と問い合わせた場合を考えてみます。
select ai 社員の電話番号教えて;
-- 結果
| 社員名 | 電話番号 |
|-----------|----------------|
| 佐藤 花子 | ***-****-**** |
| 高橋 大輔 | ***-****-**** |
このように、実データは保持したまま、出力時に自動でマスキング処理が適用されます。
アプリやAIのクエリロジックを一切変更せず、データベースレイヤーだけで実現できるのが大きな特徴です。
🗣️ AIが自然に「非公開」と応答する
Select AI の「narrate」モードを使うと、AIが結果を自然言語で説明します。
Data Redactionによるマスク結果を認識して、次のような“人間らしい”回答を返します。
select ai narrate 社員の電話番号教えて;
-- 結果
- 佐藤 花子さんの電話番号は非公開です。
- 高橋 大輔さんの電話番号は非公開です。
つまり、AIは「値が存在しない」のではなく「マスクされている」ことを理解できるため、
「情報非公開です」と自然に返答します。
この点が、Select AI と Data Redaction の相性の良さを象徴しています。
💡 Data Redactionを選ぶべきシーン
Data Redaction は以下のようなケースで特に効果を発揮します:
- 🧱 アプリやBIツールとの互換性を維持したい(列構造を壊さず、NULLを避けたい)
- 🤖 Select AI / LLM で自然な返答を維持したい(「データがない」ではなく「非公開」とLLMにより解釈させたい)
- 🧩 テスト・開発環境で形式を維持したダミーデータを使いたい
- 🧮 特定条件(部署・職位・時間帯など)で部分的にマスクしたい
✳️ まとめ
VPDが「アクセスそのものを遮断するドアロック」だとすれば、
Data Redactionは「見せるが中身は隠すすりガラス」です。
両者は排他的ではなく、補完的に利用できる関係にあります。
VPDで「どの行・列を見せるか」を制御し、
Data Redactionで「見せる際の中身(値)をどう見せるか」を制御することで、
よりきめ細かく、かつユーザー体験を損なわないセキュリティを実現できます。
特に Select AI のように自然言語でデータを返す機能では、
AIが「データが存在しない」のか「非公開なのか」を正しく理解できるようにすることが重要です。
Data Redactionはその文脈を保ちつつ、個人情報を安全に扱うことを可能にします。
🧩 VPD × Data Redaction × Select AI
行・列・値という3層の視点で制御を組み合わせることで、
“セキュリティと使いやすさを両立したAIデータアクセス”を構築できます。
📚 参考リンク
Oracle — DBMS_REDACT リファレンスガイド
Oracle — Data Redaction ポリシー管理と権限設定
Qiita — Select AI × VPDで実現するセキュアな自然言語アクセス