結論: RAGのデータセキュリティは「取り込み時にPII・機密をマスキングし、検索時にユーザー権限でメタデータフィルタを掛け、回答時に再フィルタと監査ログを残す」という多層防御で守る。検索エンジンに権限制御を委ねず、取り込み・検索・回答の3地点それぞれで防御を設計するのが原則です。
この記事の要点:
- 要点1: RAG特有のリスクは「権限のない文書が検索で混ざる」「PIIが回答に出る」「取り込み時に機密が混入する」の3つに集約され、いずれもベクトル検索の仕組みに由来する
- 要点2: アクセス制御はベクトルDBのメタデータフィルタ+アプリ側の二重チェックで実装し、PostgreSQLのRow-Level Securityのような行レベル制御の考え方を検索に持ち込む
- 要点3: 外部LLMにデータを渡す際は、API利用時の学習・保持ポリシー(OpenAI・Anthropicとも商用APIはデフォルト非学習)を契約・設計の両面で確認する
対象読者: 社内文書をRAGに載せようとしている開発者・データ基盤担当
難易度: 中級
読了時間: 約14分
「社内のドキュメントをRAGに載せて社内アシスタントを作ったら、人事評価シートの内容が一般社員の質問に対する回答に混ざって出てきた」——RAGを本番投入したチームが遭遇しがちな事故です。検索精度のチューニングには熱心でも、「誰がどの文書を検索できるか」「PIIが回答に漏れないか」というデータセキュリティの設計は後回しになりやすい領域です。
RAGは「データベースから関連文書を引いてLLMに渡す」だけのシンプルな仕組みに見えますが、ベクトル検索は通常のSQLのWHERE句のような明示的なアクセス制御を持ちません。意味的に近い文書をスコア順に返すだけなので、何も対策しなければ全社員が全文書を検索できる状態になります。社内文書には人事情報・契約書・顧客のPII・財務データなど、見える人を厳密に制御すべき情報が含まれているにもかかわらず、です。
この記事では、社内文書をRAGに載せる開発者向けに、①RAG特有のリスク ②アクセス制御の実装 ③PII・機密のマスキング ④監査ログとデータガバナンス ⑤外部LLMへのデータ提供時の確認 を、実装イメージ付きで2026年6月時点の情報をもとに解説します。最後まで読めば、「精度は出るがセキュリティはザル」というRAGを卒業し、本番投入できる設計の全体像がつかめるはずです。
重要な前提: 本記事は防御側の設計観点に徹し、攻撃の悪用手順は扱いません。また、最終的なセキュリティ設計・コンプライアンス判断は専門家・法務が行い、ここで紹介する実装パターンやAIが生成するコードも必ず人がレビュー・テストしてから本番投入してください。具体的なPII定義・保持期間・委託先要件は、扱うデータと適用される法令(個人情報保護法等)に応じて法務・セキュリティ部門と確定させる必要があります。
プロンプトインジェクションのような「入力経由の攻撃」への対策は、本記事と別軸のテーマとしてAIエージェント セキュリティ|Injection対策10選で扱っています。本記事は「データそのものをどう守るか」に焦点を当てます。

RAG特有のデータセキュリティリスク — なぜ通常のDBと違うのか
まず、RAGがなぜ独自のセキュリティ課題を持つのかを整理します。リスクは大きく3つの地点で発生します。
リスク1: 権限のない文書が検索で漏れる(検索時)
最も典型的な事故です。ベクトル検索は「クエリベクトルに意味的に近い文書」を距離スコア順に返すだけで、「このユーザーがその文書を見てよいか」という認可の概念を持ちません。全社員の質問が同じベクトルインデックスに対して実行されると、人事部しか見られないはずの評価シートや、特定プロジェクトの契約書が、無関係なユーザーの回答コンテキストに混入します。
厄介なのは、LLMが受け取ったコンテキストを「自然に要約」してしまう点です。元文書へのリンクを表示しなくても、回答本文に機密情報の中身が溶け込むため、アクセスログ上は「文書を開いていない」のに情報は漏れているという状態が起きます。
リスク2: PII・機密が回答に出力される(回答時)
取り込んだ文書にメールアドレス・電話番号・マイナンバー・口座番号などのPII(個人を特定できる情報)が含まれていると、検索でヒットした際にそのまま回答に現れます。社内向けでも「営業担当者が顧客の個人情報を必要以上に閲覧できてしまう」という最小権限原則からの逸脱になりますし、外部公開チャットボットなら重大なインシデントです。
リスク3: 取り込み時の機密混入(インジェスト時)
RAGのデータパイプラインは「とりあえず全社の共有ドライブをまるごとインデックス化する」と作りがちです。しかし共有ドライブには、誤って置かれた給与一覧、退職者リスト、未公開のM&A資料などが紛れ込んでいることがあります。一度ベクトル化してインデックスに入れてしまうと、後から「あの文書だけ消したい」という個別削除や、PIIの遡及マスキングは手間がかかります。取り込みの入口で弾くのが鉄則です。
3つのリスクと防御地点の対応
| リスク | 発生地点 | 主な防御策 | OWASP LLM Top 10 対応 |
|---|---|---|---|
| 権限外文書の漏えい | 検索時 | メタデータフィルタ+アプリ側二重チェック | LLM02 機微情報の漏えい |
| PII・機密の出力 | 回答時 | 取り込み時マスキング+出力時再検査 | LLM02 機微情報の漏えい |
| 機密文書の混入 | 取り込み時 | 取り込みフィルタ+分類タグ付け | LLM08 ベクトル/埋め込みの脆弱性 |
OWASPのGenAI向けセキュリティガイダンス(LLM Top 10)でも、機微情報の漏えい(Sensitive Information Disclosure)とベクトル・埋め込みの弱点(Vector and Embedding Weaknesses)は独立した項目として挙げられており、RAGの構成要素そのものが攻撃面・漏えい面になることが明示されています。
アクセス制御の実装 — メタデータフィルタと権限の絞り込み
RAGのアクセス制御の基本は「ベクトル検索の前後に、ユーザー権限による絞り込みを必ず挟む」ことです。検索エンジンに認可を任せず、アプリケーション層で制御します。
方式1: メタデータフィルタ(最も実用的)
各文書チャンクをベクトル化する際に、「閲覧可能なロール」「部署」「機密レベル」などをメタデータとして付与します。検索時にユーザーの権限に応じたフィルタ条件を渡すことで、そもそも権限のある文書だけを検索対象にします。主要なベクトルDB(Pinecone・Qdrant・Weaviate等)はメタデータフィルタ付き検索をサポートしています。
取り込み時のメタデータ付与イメージ:
# 取り込み時: チャンクに権限メタデータを付与してupsert
# allowed_roles / department / classification を必ず持たせる
records = []
for chunk in chunks:
records.append({
"id": chunk.id,
"values": embed(chunk.text), # 埋め込みベクトル
"metadata": {
"text": chunk.text,
"doc_id": chunk.doc_id,
"allowed_roles": chunk.acl.roles, # 例: ["hr", "exec"]
"department": chunk.department, # 例: "sales"
"classification": chunk.level, # 例: "confidential"
},
})
index.upsert(vectors=records, namespace="internal-docs")
検索時のフィルタ適用イメージ:
# 検索時: ユーザーが持つロールに基づいてフィルタを構築
def search(query: str, user) -> list:
user_roles = user.roles # 認証基盤から取得した正規のロール
# メタデータフィルタで権限のあるチャンクだけを対象にする
flt = {
"allowed_roles": {"$in": user_roles},
"classification": {"$in": user.max_classification_levels()},
}
results = index.query(
vector=embed(query),
top_k=8,
filter=flt, # ← ここでベクトルDB側が事前絞り込み
include_metadata=True,
namespace="internal-docs",
)
return results.matches
Pineconeの公式ドキュメントでも、メタデータはベクトル検索のフィルタリングに使うことが想定されており、クエリ時にメタデータ条件を渡してヒット対象を絞り込めると説明されています。重要なのは、ロールの値をクライアントから受け取った文字列ではなく、サーバー側で認証済みのセッション・トークンから導出することです。クライアントが申告したロールを信じると、フィルタは簡単に迂回されます。
方式2: 名前空間・インデックス分離(強い分離が必要なとき)
機密レベルが大きく異なるデータは、同じインデックス内のフィルタではなく、名前空間(namespace)やインデックス自体を分けます。「一般社員向け」「人事向け」「経営層向け」を物理的に別インデックスにすると、フィルタ条件のバグで越境するリスクをゼロに近づけられます。フィルタ条件の付け忘れが致命傷になる高機密データには、この分離アプローチが安全です。
方式3: 行レベルセキュリティ(RLS)の考え方を持ち込む
メタデータをベクトルDBではなくPostgreSQL等のRDBに保持し、pgvector拡張でベクトルも同じDBに置く構成では、PostgreSQLのRow-Level Security(RLS)が使えます。RLSはテーブルの行ごとにアクセスポリシーを定義でき、アプリがフィルタを書き忘れてもDB側でポリシーが強制されるのが利点です。
-- 行レベルセキュリティの考え方(pgvector + RLS の例)
ALTER TABLE doc_chunks ENABLE ROW LEVEL SECURITY;
CREATE POLICY chunk_acl ON doc_chunks
USING (
allowed_role = ANY (current_setting('app.user_roles')::text[])
);
-- アプリは検索前にセッションへユーザーのロールを設定する
-- SET app.user_roles = '{sales,general}';
-- 以降のSELECTはRLSポリシーで自動的に絞り込まれる
PostgreSQL公式ドキュメントでも、RLSはテーブル単位のポリシーで「どの行を返す・更新するか」を制限する機能として定義されています。アプリ層のフィルタとDB層のRLSを両方掛ける「多層」が、書き忘れに強い設計です。
アクセス制御の二重化が原則
どの方式でも、「ベクトルDBのフィルタ」と「結果を受け取った後のアプリ側チェック」の二重化を推奨します。具体的には、検索結果として返ってきたチャンクのメタデータを、もう一度ユーザー権限と照合し、想定外のものが混ざっていれば破棄してログに記録します。フィルタのバグ・設定ミスを最後の砦で止めるためです。
PII・機密のマスキング — 取り込み時と回答時の二段構え
アクセス制御で「誰が検索できるか」を制御しても、その文書内のPIIまでは止められません。PII・機密のマスキングは、取り込み時(インデックスに入れる前)と回答時(ユーザーに返す前)の二段構えで実装します。
取り込み時マスキング(推奨・恒久対策)
文書をチャンク化してベクトル化する前に、PIIを検出して匿名化・トークン化します。インデックスにPIIを入れない状態を作るのが最も安全で、後からの遡及対応も不要になります。検出には正規表現(メール・電話・カード番号など定型パターン)と、固有表現抽出(人名・住所など文脈依存)を組み合わせます。Google CloudのDLP(Sensitive Data Protection)のようなマネージドサービスを使うと、PIIの検出種別と匿名化(マスキング・トークン化)を一貫して扱えます。
import re
# 簡易な定型PIIマスキング(本番では専用ライブラリ/マネージドDLPを併用)
PATTERNS = {
"EMAIL": re.compile(r"[\w.+-]+@[\w-]+\.[\w.-]+"),
"PHONE_JP": re.compile(r"0\d{1,4}-\d{1,4}-\d{4}"),
"MYNUMBER": re.compile(r"\b\d{4}\s?\d{4}\s?\d{4}\b"),
}
def mask_pii(text: str) -> str:
for label, pat in PATTERNS.items():
text = pat.sub(f"[{label}_REDACTED]", text)
return text
# 取り込みパイプライン: マスキング後にベクトル化する
clean_text = mask_pii(raw_chunk_text)
vector = embed(clean_text)
ただし正規表現だけでは、文脈に依存する人名・住所・症状などの非定型PIIは取りこぼします。重要度の高いデータでは、固有表現抽出やマネージドDLPサービスを併用し、検出ルールは扱うデータに合わせて法務・セキュリティ部門と定義してください。なお、マスキングの程度は用途で調整が必要です。PIIを完全に消すと「○○さんの連絡先は?」という正当な業務質問に答えられなくなるため、トークン化(参照可能な仮名に置換し、権限のある画面でのみ復元)という選択肢も検討します。
回答時マスキング(最後の砦)
取り込み時に取りこぼしたPIIや、LLMが生成過程で組み立ててしまった機微情報を、ユーザーに返す直前に再検査します。出力テキストをPII検出器に通し、検出されたら警告・マスキング・ブロックのいずれかを行います。これは取り込み時マスキングの代替ではなく、多層防御の最終層です。
def respond(query, user):
chunks = search(query, user) # 権限フィルタ済み検索
answer = llm_generate(query, chunks) # LLM生成
# 出力時の再検査: 残存PIIを最後に止める
safe_answer = mask_pii(answer)
if safe_answer != answer:
audit_log(user, "pii_redacted_on_output", query=query)
return safe_answer
マスキングの設計判断
| 地点 | 役割 | 長所 | 注意点 |
|---|---|---|---|
| 取り込み時 | 恒久対策 | インデックスにPIIが残らない・遡及不要 | 業務に必要な情報まで消すと使えない |
| 検索時フィルタ | 権限制御 | そもそも見せない文書を弾く | 文書内のPIIは止められない |
| 回答時 | 最後の砦 | 取りこぼし・LLM生成分を捕捉 | レイテンシ増・誤検出のチューニング要 |
監査ログとデータガバナンス — 「いつ誰が何を引いたか」を残す
RAGは「誰が・いつ・どのクエリで・どの文書を取得し・どんな回答を得たか」を記録しないと、インシデント発生時の影響範囲が特定できません。通常のファイルアクセスログと違い、RAGでは「文書を開いていないのに内容が回答に出る」ため、検索イベント単位のログが不可欠です。
監査ログに残すべき項目
- ユーザーID・セッションID・実行時刻(誰が・いつ)
- クエリ内容(何を聞いたか。PII含有クエリ自体の扱いも要検討)
- 適用したアクセスフィルタ条件(どの権限で検索したか)
- 取得したチャンクのdoc_id・classification(どの機密レベルの文書を引いたか。本文そのものはログに残さない方針も検討)
- 回答時マスキングの発火有無(PIIを止めたか)
- 二重チェックで破棄したチャンクの有無(フィルタ越境の兆候検知)
NISTのAIリスクマネジメントフレームワーク(AI RMF)および生成AI向けプロファイル(NIST AI 600-1)では、AIシステムの透明性・説明可能性・追跡可能性が繰り返し求められています。監査ログは、その追跡可能性を技術的に担保する基盤です。NIST SP 800-53のアクセス制御(AC)・監査(AU)系のコントロールは、AI固有でなくとも、RAGのデータ基盤に適用できる成熟したコントロールセットです。
データガバナンスの最小セット
- データ分類: 取り込む文書に機密レベル(公開/社内/機密/極秘)のタグを必ず付与し、未分類文書は取り込まない
- 保持期間と削除: 文書のライフサイクルに合わせ、退職者情報・期限切れ契約などをインデックスから確実に削除できる仕組み(doc_id単位の削除API)を最初から用意する
- 所有者の明確化: どの部署・誰がそのデータソースの責任者かを台帳化し、アクセス権の棚卸しを定期実施する
- 変更追跡: 元文書が更新・削除されたら、対応するチャンクをインデックスから再同期する(古い機密情報が残り続ける事故の防止)
RAGのアーキテクチャ全体での位置づけはAIエージェント実装ロードマップ|RAG・実行・運用の必須技術で、検索精度を左右する埋め込みモデルの選定はEmbeddingモデル選定ガイドで扱っています。セキュリティ設計はこれらの実装と並行して、最初から組み込むのが理想です。
外部LLMにデータを渡す際の規約・データ保持の確認
RAGはほとんどの場合、取得したチャンク(=社内文書の一部)を外部LLM APIに送信します。ここで「自社の機密データが、外部プロバイダーの学習に使われないか」「どれくらい保持されるか」を契約・設計の両面で確認する必要があります。
主要プロバイダーのデータ取り扱い(2026年6月時点)
2026年6月時点で、主要プロバイダーは「商用API経由の入出力をデフォルトでモデル学習に使わない」というポリシーを明示しています。OpenAIは、API経由で送信されたデータをデフォルトでモデルの訓練に使わないことを公式ドキュメントで説明しています。Anthropicも商用利用規約で、商用サービス経由の顧客データをモデル訓練に使用しない旨を定めています。一方で、悪用検知などの目的での一時的なデータ保持期間はプロバイダー・プランごとに異なるため、必ず最新の公式規約を一次ソースで確認してください。
| 確認項目 | 確認すべき内容 |
|---|---|
| 学習利用 | API入出力がモデル訓練に使われないか(商用APIはデフォルト非学習が一般的) |
| 保持期間 | 悪用監視等での一時保持期間と、保持の停止(Zero Data Retention等)の可否 |
| サブプロセッサ | データを処理する委託先・所在地(データレジデンシー要件との整合) |
| 処理地域 | リージョン指定の可否(国内処理が必要なデータの扱い) |
| 契約形態 | DPA(データ処理契約)の締結、エンタープライズ契約での追加保護 |
設計上の打ち手
- 外部LLMに送る前に、取り込み時マスキングで最も機微なPIIを除去しておく(プロバイダーのポリシーに依存しない一次防御)
- 極秘レベルの文書は外部APIに送らず、自社管理のローカルLLMやVPC内推論に限定する選択肢を持つ
- エンタープライズ契約・データ処理契約(DPA)を結び、保持・委託先・処理地域を契約で固定する
- 送信データのリージョンを指定できるプロバイダー・プランを選ぶ(データレジデンシー要件がある場合)
ガードレールでの入出力検査と組み合わせる場合は、各ガードレール製品の比較をAIエージェント ガードレール比較でまとめています。データマスキングとガードレールは役割が異なる(前者はデータ加工、後者は入出力ポリシー検査)ため、両方を組み合わせると堅牢です。
【注意】RAGデータセキュリティでよくある失敗パターン
失敗1: 検索エンジンに認可を任せる
❌ ベクトル検索のスコアだけで結果を返し、権限チェックを入れない
⭕ メタデータフィルタ(DB側)+結果受領後の二重チェック(アプリ側)で多層化し、ロールはサーバー側の認証情報から導出する
失敗2: PIIマスキングを回答時だけに置く
❌ インデックスにPIIを入れたまま、出力時のフィルタだけで止めようとする
⭕ 取り込み時にマスキング・トークン化してインデックスにPIIを残さない。回答時検査は最後の砦として併用する
失敗3: 共有ドライブをまるごと取り込む
❌ 「全社ドキュメントを一括インデックス化」で未分類・誤配置の機密まで取り込む
⭕ データソースを限定し、機密レベルのタグ付け・所有者確認を取り込みの前提条件にする。未分類文書は弾く
失敗4: 監査ログを「文書を開いた記録」だけで済ませる
❌ ファイルアクセスログだけ残し、検索イベントを記録しない
⭕ クエリ・適用フィルタ・取得チャンクのdoc_id・マスキング発火を検索単位で記録する。RAGは「開かずに内容が漏れる」ことを前提にする
失敗5: 外部LLMのポリシーを確認せず本番投入する
❌ プロバイダーが「学習に使わない」と思い込み、規約・保持期間を読まずに機密を送る
⭕ 公式規約を一次ソースで確認し、DPA締結・リージョン指定・ZDRオプションを検討。最も機微なデータは送信前にマスキングする
まとめ: 今日から始める3つのアクション
- 今日: 自分のRAGがインデックス化している文書に、人事・契約・PIIが含まれていないかを棚卸しする。共有ドライブまるごと取り込みになっていないか確認する
- 今週中: 検索パイプラインに「ユーザー権限によるメタデータフィルタ」と「結果受領後の二重チェック」を入れる。ロールがサーバー側認証から導出されているかをコードレビューする
- 今月中: 取り込み時のPIIマスキング、検索イベントの監査ログ、外部LLMのデータ取り扱い規約確認(DPA・保持期間)を、法務・セキュリティ部門と連携して設計に組み込む
AIエージェント・ツールの最新情報をキャッチアップしたい方へ
Agent Labでは、週1回のニュースレターでAIツールの最新比較・活用事例・実装ガイドをお届けしています。
著者: 佐藤傑(さとう・すぐる)
株式会社Uravation代表取締役。X(@SuguruKun_ai)フォロワー約10万人。100社以上の企業向けAI研修・導入支援。著書『AIエージェント仕事術』(SBクリエイティブ)。
ご質問・ご相談は お問い合わせフォーム からお気軽にどうぞ。
参考・出典
- OWASP Top 10 for LLM Applications — OWASP GenAI Security Project(参照日: 2026-06-05)
- AI Risk Management Framework (AI RMF) — NIST(参照日: 2026-06-05)
- NIST AI 600-1: Generative AI Profile — NIST(参照日: 2026-06-05)
- NIST SP 800-53 Rev.5 Security and Privacy Controls — NIST(参照日: 2026-06-05)
- Row Security Policies — PostgreSQL公式ドキュメント(参照日: 2026-06-05)
- Understanding metadata — Pinecone Docs(参照日: 2026-06-05)
- Sensitive Data Protection documentation — Google Cloud(参照日: 2026-06-05)
- How we use your data — OpenAI Platform Docs(参照日: 2026-06-05)
- Commercial Terms of Service — Anthropic(参照日: 2026-06-05)
