Skip to content

필사 모드: SAML 2.0 ディープダイブ — Assertion・Binding・Metadata 完全攻略

日本語
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

はじめに

OIDC が新規構築のデフォルトとなった 2026 年でも、エンタープライズ B2B SSO の現場では依然として SAML 2.0 が共通語です。顧客企業の Entra ID、Okta、あるいは自社構築の IdP と連携せよという要件を受け取ると、半分以上の確率で SAML メタデータの XML ファイルが送られてきます。2005 年に標準化されたプロトコルが 20 年以上も現役である理由は単純です。**すでに敷設された信頼関係の慣性**と、**ブラウザさえあれば動くというシンプルな前提**です。

問題は、SAML が「設定すれば動くブラックボックス」として扱われ、障害が起きると誰も中身を知らないという点です。本記事では SAML 2.0 の核心である Assertion、Protocol(AuthnRequest/Response)、Binding、Metadata を実際の XML レベルで解剖し、XML Signature Wrapping のような攻撃と防御、さらにクロックスキューのような運用課題まで扱います。

SAML 2.0 の 4 層構造

SAML スペックは 4 つのレイヤーで構成されます。この区分を知っていると、スペック文書がはるかに読みやすくなります。

+-----------------------------------------------------------+

| Profiles : レイヤーを組み合わせた利用シナリオ |

| (Web Browser SSO Profile、Single Logout など) |

+-----------------------------------------------------------+

| Bindings : メッセージを運ぶ転送方法 |

| (HTTP-Redirect, HTTP-POST, Artifact, SOAP) |

+-----------------------------------------------------------+

| Protocols : 要求/応答メッセージの形式 |

| (AuthnRequest, Response, LogoutRequest など) |

+-----------------------------------------------------------+

| Assertions : アイデンティティ情報の本体 |

| (AuthnStatement, AttributeStatement など) |

+-----------------------------------------------------------+

- **Assertion**: 「このユーザーは誰で、いつどのように認証され、どんな属性を持つか」という陳述の XML 文書。

- **Protocol**: Assertion を要求し応答するメッセージの規格。

- **Binding**: そのメッセージを HTTP の上にどう載せるかのルール。

- **Profile**: 上の 3 つを束ねて「Web ブラウザ SSO」という完結したシナリオにしたもの。

私たちが普段「SAML 連携」と呼ぶものは、ほぼ常に **Web Browser SSO Profile** です。

Assertion の解剖 — アイデンティティ陳述の XML

以下は実際の IdP が発行する Assertion の骨格です(署名は省略)。

xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"

ID="_a1b2c3d4e5f6"

Version="2.0"

IssueInstant="2026-06-12T09:30:00Z">

f9a8b7c6-1234-5678-90ab-cdef12345678

NotOnOrAfter="2026-06-12T09:35:00Z"

Recipient="https://app.example.com/saml/acs"

InResponseTo="_req-98765"/>

NotBefore="2026-06-12T09:29:00Z"

NotOnOrAfter="2026-06-12T09:35:00Z">

AuthnInstant="2026-06-12T09:30:00Z"

SessionIndex="_sess-112233">

urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport

要素ごとの意味と検証ポイント

| 要素 | 意味 | SP が検証すべきこと |

| --- | --- | --- |

| Issuer | Assertion 発行者(IdP)の entityID | 信頼する IdP の entityID と正確に一致するか |

| Subject/NameID | ユーザー識別子 | Format が合意済みのものか(persistent、emailAddress など) |

| SubjectConfirmation | 「この Assertion を提示する者」の条件 | Recipient が自分の ACS URL か、NotOnOrAfter が有効か、InResponseTo が自分が送った要求 ID か |

| Conditions | 有効期間と受信対象 | NotBefore/NotOnOrAfter の時間枠、Audience が自分の entityID か |

| AuthnStatement | いつ/どのように認証されたか | AuthnContextClassRef がポリシー(MFA 要求など)を満たすか |

| AttributeStatement | ユーザー属性 | マッピングルールどおりに解析し、認可の入力として使用 |

NameID Format は運用で頻繁に問題になる部分です。persistent はサービスごとに固定された不透明な識別子、transient はセッションごとに変わる使い捨て、emailAddress は人間が読めるメールアドレスです。SP が emailAddress を期待しているのに IdP が persistent を送ると、「ログインはできるのにアカウントのマッチングができない」障害が発生します。連携の初期段階で必ず合意してください。

AuthnRequest / Response のフロー

SP-initiated SSO(標準経路)

ユーザーが SP に先にアクセスした場合です。SP が AuthnRequest を作り、ブラウザを IdP へ送ります。

xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"

xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"

ID="_req-98765"

Version="2.0"

IssueInstant="2026-06-12T09:29:50Z"

Destination="https://idp.corp.com/saml/sso"

AssertionConsumerServiceURL="https://app.example.com/saml/acs"

ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST">

Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"

AllowCreate="true"/>

urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport

IdP は認証を終えると Response を返します。Response の中に Assertion が入っています。

xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"

ID="_resp-55555"

Version="2.0"

IssueInstant="2026-06-12T09:30:00Z"

Destination="https://app.example.com/saml/acs"

InResponseTo="_req-98765">

https://idp.corp.com/saml

<!-- 署名された saml:Assertion がここに入る -->

重要な対応関係: AuthnRequest の ID は、Response の InResponseTo、および Assertion 内 SubjectConfirmationData の InResponseTo と一致しなければなりません。この検証を省略すると、別セッション用の Response を注入する攻撃が可能になります。

SP-initiated vs IdP-initiated

SP-initiated(推奨) IdP-initiated

-------------------- --------------------

ユーザー -> SP にアクセス ユーザー -> IdP ポータルにアクセス

SP が AuthnRequest を生成(ID を記録) アプリのタイルをクリックすると

IdP 認証後に Response AuthnRequest なしでいきなり

(InResponseTo=要求 ID) Unsolicited Response を発行

SP: InResponseTo の検証が可能 SP: InResponseTo の検証が不可能

(そもそも要求が存在しない)

CSRF/注入の防御が容易 Response 注入に相対的に脆弱

IdP-initiated は「会社ポータルでアプリのアイコンをクリックして入る」UX のためエンタープライズでよく要求されますが、InResponseTo の検証ができないためセキュリティ上は劣位です。可能であれば IdP ポータルのアプリタイルが SP のログイン開始 URL を指すようにし、**実質的に SP-initiated へ迂回実装する**のがベストプラクティスです。

Binding — メッセージを運ぶ 3 つの方法

HTTP-Redirect Binding

AuthnRequest のような小さいメッセージに使います。メッセージを DEFLATE 圧縮 → base64 → URL エンコードしてクエリ文字列に載せます。

GET /saml/sso?SAMLRequest=fZJNb9swDIb%2FisG7...&RelayState=abc123

&SigAlg=http%3A%2F%2Fwww.w3.org%2F2001%2F04%2Fxmldsig-more%23rsa-sha256

&Signature=KJh8... HTTP/1.1

Host: idp.corp.com

- URL 長の制限があるため、大きなメッセージ(署名を含む Response)には不向きです。

- 署名は XML 内部ではなく**クエリパラメータ(SigAlg、Signature)**として別途渡されます(detached signature)。

HTTP-POST Binding

Response のような大きいメッセージに使います。IdP が自動送信される HTML フォームを返し、ブラウザが SP の ACS へ POST します。

- base64 のみ適用(圧縮なし)、署名は XML 内部に含まれます。

- 事実上すべての Web SSO 連携における Response の受け渡しはこのバインディングです。

HTTP-Artifact Binding

機微な内容をブラウザに露出させたくない場合に使います。ブラウザには短い参照値(artifact)だけを渡し、SP が back-channel(SOAP)で IdP から実際のメッセージを取得します。

[ブラウザ] [SP] [IdP]

|<-- artifact 受領 -| |

|--- artifact ----->| |

| |--- ArtifactResolve(SOAP)->|

| |<-- ArtifactResponse ------|

| | (実際の SAMLResponse)|

- セキュリティは高いものの、SP-IdP 間の直接のネットワーク接続が必要で実装の複雑さも高く、実務では稀です。

バインディングの比較

| 項目 | HTTP-Redirect | HTTP-POST | HTTP-Artifact |

| --- | --- | --- | --- |

| 用途 | AuthnRequest, LogoutRequest | Response の受け渡し | 高セキュリティ環境 |

| エンコーディング | DEFLATE + base64 + URL | base64 | artifact 参照値 |

| 署名の位置 | クエリパラメータ(detached) | XML 内部(enveloped) | XML 内部 |

| サイズ制限 | URL 長の制限あり | 事実上なし | 該当なし |

| back-channel の要否 | 不要 | 不要 | 必要(SOAP) |

| 実務での頻度 | 高い(要求) | 非常に高い(応答) | 低い |

Metadata — 信頼関係の設定ファイル

SAML 連携の出発点はメタデータの交換です。SP メタデータの例は次のとおりです。

xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"

entityID="https://app.example.com/saml/metadata">

AuthnRequestsSigned="true"

WantAssertionsSigned="true"

protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">

Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"

Location="https://app.example.com/saml/slo"/>

index="0" isDefault="true"

Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"

Location="https://app.example.com/saml/acs"/>

IdP メタデータには SingleSignOnService エンドポイントと IdP の署名証明書が入っています。運用上のポイントは次のとおりです。

- **entityID は識別子であり URL ではありません。**慣例として URL の形を使いますが、文字列が正確に一致するかがすべてです。末尾のスラッシュ 1 つの違いで連携が壊れます。

- **証明書の期限切れが SAML 障害の原因第 1 位です。**メタデータ内の証明書は TLS 証明書とは別に期限切れになります。期限の 90/30/7 日前のアラートを自動化してください。

- **鍵のロールオーバー**: KeyDescriptor は複数置けます。新しい証明書をメタデータに追加 → 相手側の更新を確認 → 署名鍵を切り替え → 旧証明書を削除、という順序で無停止ローテーションが可能です。

- メタデータ自体に署名するか、信頼できるチャネル(管理コンソール、署名付き URL)でのみ交換してください。

XML Signature と暗号化

署名の構造

SAML は XML Signature(XMLDSig)の enveloped signature を使います。署名対象のダイジェストを計算し、そのダイジェスト情報を含む SignedInfo を秘密鍵で署名します。

注目すべきは、Reference の URI が **ID 属性の参照**である点です。「ID が _a1b2c3d4e5f6 の要素」が署名対象であることを意味し、まさにこの間接参照が Signature Wrapping 攻撃の糸口になります。

署名の範囲は Response 全体と各 Assertion のそれぞれに適用できます。**両方に署名するのが推奨**であり、最低でも Assertion への署名は必須です。

暗号化(EncryptedAssertion)

Assertion はブラウザを経由(front-channel)するため、属性に機微情報が含まれる場合は XML Encryption で Assertion を SP の公開鍵で暗号化できます。署名が「偽造防止」なら、暗号化は「内容の秘匿」です。役割が異なるため、暗号化は署名の代わりにはなりません。

XML Signature Wrapping(XSW)攻撃と防御

SAML 史上もっとも有名な攻撃の系譜です。核心となるアイデアは、**署名検証ロジックが見る「署名が有効な要素」と、アプリケーションが実際に読む要素が異なるように XML 構造を操作する**ことです。

正常な Response XSW 攻撃の Response

-------------- ------------------

Response Response

└─ Assertion (ID=A, 署名済み) ├─ [偽造 Assertion] (ID=B, 署名なし)

└─ Subject: alice │ └─ Subject: admin <-- アプリが読むもの

└─ [元の Assertion] (ID=A, 署名は有効)

└─ Subject: alice <-- 検証器が見るもの

署名検証器: 「ID=A の要素の署名? 有効」 --> 通過

アプリケーション: 最初の Assertion(偽造)を解析 --> admin としてログイン

2012 年の研究では、当時の主要な SAML ライブラリ 14 個のうち多数がこの系統の攻撃に破られ、その後も亜種が周期的に発見されています。

防御チェックリスト

1. **自作しないこと** — 検証済みライブラリ(OpenSAML など)の最新版を使い、セキュリティパッチを追跡します。

2. **「署名されたまさにそのノード」だけを使う** — 署名検証に成功した要素の DOM ノードからのみデータを読みます。「文書から最初の Assertion を探す」式の解析は厳禁です。

3. **スキーマ検証を先に** — SAML スキーマに反する構造(重複 Assertion、おかしな位置の要素)を署名検証の前に拒否します。

4. **Assertion の個数を強制** — Web SSO では Assertion は 1 つです。2 つ以上なら拒否します。

5. **Response と Assertion の両方に署名を要求** — WantAssertionsSigned と Response 署名の要求を両方有効にします。

6. **XML パーサーのハードニング** — DTD と外部エンティティ(XXE)を無効化します。

RelayState — 忘れられがちな脇役

RelayState は「ログイン後にどこへ戻るか」を運ぶ不透明なパラメータです。SP-initiated では SP が送った値が Response とともにそのまま戻り、IdP-initiated では IdP が目的地の URL を入れることもあります。

運用/セキュリティのポイント:

- スペック上 80 バイトの制限があるため、URL 全体ではなく**サーバー側状態へのキー**を入れるのが安全です。

- 戻ってきた RelayState を検証なしにリダイレクトに使うと **open redirect** の脆弱性になります。ホワイトリストまたは署名/サーバー側照会で検証してください。

- RelayState は署名の対象外なので、改ざんされうる前提で扱う必要があります。

クロックスキュー — 間欠的障害の常連犯

Assertion の NotBefore/NotOnOrAfter は通常、発行時刻を基準に ±数分の短い窓です。IdP と SP の時計がずれるとこうなります。

IdP の時計: 09:30:00 --> NotBefore=09:29:00 で発行

SP の時計: 09:28:30 --> 「NotBefore が未来」 --> 拒否

症状: 同じユーザーがリトライすると成功することもある(間欠的)

時計がずれた特定の SP ノードにルーティングされた時だけ失敗

対応:

1. すべてのノードに NTP/chrony を強制し、ドリフトを監視します。

2. SAML ライブラリの clock skew 許容値を 60〜120 秒に設定します(多くはデフォルト 0 か非常に小さい値)。

3. 障害分析のために「どのノードで失敗したか」と当該ノードの時刻を併せて記録するログを整備します。

検証失敗ログには最低限、Issuer、InResponseTo、拒否理由(時刻条件/Audience/署名)、そしてサーバー時刻を残してください。「Invalid SAML response」一行だけのログは運用者への拷問です。

SP 実装時の検証チェックリスト

SAML Response 受信時(ACS エンドポイント):

[ ] 1. ハードニング済み XML パーサーで解析(DTD/XXE 遮断)

[ ] 2. スキーマ検証

[ ] 3. Response の署名検証(要求している場合)

[ ] 4. Status が Success であることを確認

[ ] 5. Assertion の署名検証 — 信頼された IdP 証明書で

[ ] 6. 以降のデータは署名されたノードからのみ読む

[ ] 7. Issuer が期待した IdP の entityID か

[ ] 8. Conditions: NotBefore/NotOnOrAfter(skew 許容値込み)

[ ] 9. AudienceRestriction が自分の entityID か

[ ] 10. SubjectConfirmationData: Recipient が自分の ACS URL か、

NotOnOrAfter が有効か、InResponseTo が自分が発行した要求 ID か

[ ] 11. Assertion ID の再利用チェック(リプレイ防止キャッシュ)

[ ] 12. NameID Format が合意済みの形式か

[ ] 13. すべての検証を通過した後にのみアプリセッションを確立

SAML が 2026 年も生きている理由

1. **B2B 信頼関係の慣性** — 数万社の企業 IdP と SaaS がすでに SAML で接続されています。動いている信頼関係を撤去するビジネス上の動機は弱いのです。

2. **調達要件** — エンタープライズ SaaS の購買チェックリストに「SAML SSO 対応」が今も明記されます。SSO をプレミアムプランに閉じ込める慣行(いわゆる SSO tax)への批判があること自体、SAML が標準要件である証左です。

3. **レガシー IdP エコシステム** — Broadcom SiteMinder(現行 12.9)のようなレガシー WAM 製品群が今も大企業で稼働しており、これらの標準的な連携経路が SAML です。ヘッダーベース認証から標準プロトコルへの移行の過程でも、SAML が最初の停車駅になることが多いのです。

4. **プロトコル自体の完結性** — Web SSO という用途に限れば、SAML はすでに完成したプロトコルです。変化がないことは安定性でもあります。

ただし方向性は明確です。新機能(passkeys 連携、トークン交換、FAPI など)はすべて OIDC 陣営で起きており、Keycloak のようなモダン IdP は SAML と OIDC の両方をサポートするため、**IdP をハブに置き、レガシー SP は SAML、新規アプリは OIDC** で接続するハイブリッドが 2026 年の標準アーキテクチャです。

[Keycloak 26.6 / Okta / Entra ID]

| |

SAML 2.0 | | OIDC

v v

[レガシー/B2B SaaS] [新規 Web/モバイル/API]

おわりに

SAML 2.0 を一文で要約すると「XML Assertion をブラウザのリダイレクトとフォーム POST で運び、XML Signature で信頼を保証する Web SSO プロトコル」です。実務で覚えておくべきことは 3 つです。

- **Assertion の条件(時刻、Audience、Recipient、InResponseTo)を 1 つも漏らさず検証**しなければなりません。署名検証だけでは不十分です。

- **Signature Wrapping の教訓**: 署名が有効なノードとデータを読むノードは同一でなければなりません。自作せず、検証済みライブラリを使ってください。

- **運用障害の三大要因**は証明書の期限切れ、クロックスキュー、entityID/URL の不一致です。いずれも監視と自動化で予防できます。

次回の記事では OIDC の内部 — Authorization Code Flow、Discovery、JWKS、トークン検証 — を同じ深さで扱います。

参考資料

- [SAML 2.0 Core Specification (OASIS)](https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf)

- [SAML 2.0 Bindings (OASIS)](https://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf)

- [SAML 2.0 Profiles (OASIS)](https://docs.oasis-open.org/security/saml/v2.0/saml-profiles-2.0-os.pdf)

- [SAML 2.0 Metadata (OASIS)](https://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf)

- [XML Signature Syntax and Processing (W3C)](https://www.w3.org/TR/xmldsig-core1/)

- [XML Encryption Syntax and Processing (W3C)](https://www.w3.org/TR/xmlenc-core1/)

- [On Breaking SAML: Be Whoever You Want to Be (USENIX Security 2012)](https://www.usenix.org/conference/usenixsecurity12/technical-sessions/presentation/somorovsky)

- [OWASP SAML Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/SAML_Security_Cheat_Sheet.html)

- [Keycloak Documentation — SAML Clients](https://www.keycloak.org/documentation)

- [Keycloak Release Notes](https://www.keycloak.org/docs/latest/release_notes/index.html)

- [Broadcom SiteMinder Documentation](https://techdocs.broadcom.com/siteminder)

- [OpenID Connect Core 1.0(比較参考)](https://openid.net/specs/openid-connect-core-1_0.html)

현재 단락 (1/196)

OIDC が新規構築のデフォルトとなった 2026 年でも、エンタープライズ B2B SSO の現場では依然として SAML 2.0 が共通語です。顧客企業の Entra ID、Okta、あるいは自社...

작성 글자: 0원문 글자: 11,262작성 단락: 0/196