Dify で構築する RAG ベースの FAQ Bot を既存の社内 Web アプリに iframe で組み込むときの、ブラウザ側のセキュリティ設計まわりのメモ。
全体
Dify 公式「Embedding Your Web App」では、公開済みの Web App を外部サイトに組み込む3系統の実装例(Chat Bubble Widget / Iframe Integration / JavaScript Control)が提示されている。
<iframe src="https://udify.app/chatbot/..."> を貼って動かすこと自体はできるが、親サイト側の Content Security Policy や Cookie 挙動など、Dify の外側で決めておく論点がある。
① App Token と Service API Key
Dify には発行経路の異なる2種類の識別子がある。
- App Token: Web App 単位の識別子。iframe URL に載る前提。Service API 呼び出し権限なし
- Service API Key: /v1/... を叩く Bearer トークン。サーバー側保持
iframe 埋め込みのみなら Service API Key は使わず露出しない。親サイトから Dify Service API を直接叩く要件が出た場合のみ、フロントに Service API Key が漏れない設計に分ける。
対処
- App Token は iframe URL に入る前提で扱う
- Service API Key を使う場合は親サイトのバックエンド経由(BFF)に限定する
- フロントから叩きたい場合も、BFF で認証・レート制御を噛ませた自前 API を経由する
② CSP の frame-src と frame-ancestors
- Content Security Policy (CSP)は、ブラウザに対して「このページではどのオリジンからのリソース読み込み・実行を許可するか」をレスポンスヘッダで指示する仕組み。
script-src/img-src/connect-srcなどディレクティブごとに許可元を列挙し、ポリシー違反の読み込みはブラウザがブロックする。 - iframe 埋め込みに関係するディレクティブが
frame-srcとframe-ancestorsの2つ。
複数の Content-Security-Policy ヘッダが同時に返るケース(CDN・WAF・アプリで個別に付与)では、各ポリシーが独立に評価され、すべてのポリシーで許可された場合のみリソースが許可される(intersection 評価、CSP Level 3 §8.1)。途中の経路で別 CSP が付与されると意図しないブロックが起きやすい。
対処
- 親サイト側:
frame-srcにhttps://udify.app(またはセルフホストのホスト)を明示する - 子(Dify Web App)側: 許可する親オリジンを列挙した
frame-ancestorsをレスポンスヘッダで返す。セルフホストならリバースプロキシ層等で設定する
# iframe 方式のみ(親サイト側)
Content-Security-Policy:
default-src 'self';
frame-src https://udify.app;
Chat Bubble 方式(親ページ内に Dify の embed.js を読み込む方式)なら、script-src に Dify 側ホストを追加する。
# Chat Bubble 方式(embed.js を親ページに読み込む場合)
Content-Security-Policy:
default-src 'self';
frame-src https://udify.app;
script-src 'self' https://udify.app;
-
frame-ancestorsに列挙するオリジンは、スキームとポートを本番・開発で揃える。:8443のような非標準ポートを開発用に開けている場合、親側もポートを含めて一致させないと CSP で拒否される。
③ 3rd-party Cookie とセッション設計
iframe 埋め込みの Dify は親サイトから見て third-party 文脈。Cookie が届くには Dify 側の発行属性とブラウザ側の許可が両方必要。
ブラウザ別の既定:
| ブラウザ | 既定の挙動 |
|---|---|
| Chrome | 通常モードは許可、Incognito はブロック。Privacy Sandbox の個別プロンプトは 2025-04 / 2025-10 で見送り |
| Firefox | Total Cookie Protection が既定で有効。トップレベルサイト単位にパーティション分割 |
| Safari | ITP により既定でブロック。Storage Access API での個別許可が必要 |
third-party Cookie に依存しないことを基本線にし、必要ならCHIPS (Cookies Having Independent Partitioned State)やStorage Access APIで補う。
対処
- 親サイトのセッションを Dify 側に引き継ぐ場合、でサーバーから識別子を渡す設計にする(Cookie に頼らない)
- 独自に認証付きで Dify API を叩くなら BFF 経由にして、親サイトの 1st-party Cookie で認証する