SAML:フラクタルのように悪い設計
SAML は企業 IT で20年以上使われてきたが、著者によればその土台は砂の上にある。XML 署名の検証、正規化、エンベロープ署名、なんでも詰め込み設計、そして硬直化。どれも繰り返し脆弱性を生んできた。
日本語
コピー

SAML(Security Assertion Markup Language)認証プロトコルは学術界で生まれ、企業の IT 部門で育ち、今なおそれらの組織に根強く残っている。だが、引退させるべき時だ。2000年代後半に SaaS 企業が台頭すると、IT 部門はユーザーを数多くの新しい Web サービスにログインさせる手段を必要とした。SAML と、当時まだ黎明期だったシングルサインオン(SSO)業界がその需要に応えた。しかし SAML は、自らの複雑さに押しつぶされつつある。見切りをつけて、OpenID Connect(OIDC)のような現代的な代替手段へ移るべきだ。本稿では、委員会設計に由来する SAML の成り立ち、学術界と企業環境で登り詰めていった過程、セキュリティ研究コミュニティがいかにしてそれを少しずつ崩していったか、そして(願わくば)より新しいプロトコルに取って代わられて退場するまでをたどる。
SAML 101
SAML の厄介さは、理解するだけなら大半はごく素直なのに、砂と骨灰と灰の上に築かれている点にある。使える……ただし XML 署名検証が信頼できると仮定するなら、という条件付きで。だが XML 署名検証には深い呪いがかかっていて、実運用されている SAML 実装の大半は libxmlsec をラップしている——誰も読まない、難解な C のコードベースだ。 —— Thomas Ptacek、2023
SAML と SSO 業界の誕生
Wikipedia にはこうある。「SAML はセキュリティアサーションに用いられる XML ベースのマークアップ言語である」。OASIS(構造化情報標準促進機構)の Security Services Technical Committee(SSTC)が 2002 年に策定した。現代の基準で見れば、出だしは芳しくない。XML にはそれなりの利点もあるが、JSON のような新しい代替手段に比べてはるかに複雑で、その点は後で詳しく触れる。ましてや、複数の分科会からなる委員会が集まって会議を開くのは、「何でもかんでも詰め込む」プロトコル設計の温床そのものだ(ウォーターフォール開発、事前の大設計など)。案の定、今では四つ(!)の XML ベースのセキュリティプロトコルが一つに詰め込まれている。
……以下の知的財産が SSTC に提供された:
- Netegrity の Security Services Markup Language(S2ML)
- Securant の AuthXML
- VeriSign の XML Trust Assertion Service Specification(X-TASS)
- Jamcracker の Information Technology Markup Language(ITML) —— SAML:歴史
とはいえ、こうしたプロトコルへの渇望は疑いようもなかった。インターネットが 90 年代の Web 1.0 から 2000 年代初頭の Web 2.0 へ移るにつれ、ユーザーと組織は数多くの新興 Web サービスに対して手軽に認証する手段を必要とした。この流れを最も強く推し進めたのは学術界だが、唯一ではなかった。2002 年にイェール大学の Central Authentication Service(CAS)、2003 年に Internet2(私の母校も名を連ねる研究大学の連合)の Shibboleth IdP、2003 年に Microsoft の ADFS、2007 年頃に Uninett の simpleSAMLphp——Uninett は学術界と密接な関係を持つノルウェーの国有企業だ。これらの認証プロジェクトは最終的にいずれも何らかの形で SAML をサポートした。かつての ARPANET と同じく、大学はインターネットの発展の最前線に立ち、Web サービス最初の消費者でもあった。プロトコルの実用性という基盤と、萌芽期の学術的な実験場が整うと、商業産業が引き継いで数十億ドル規模の業界へと押し上げた。SSO、アイデンティティ、認証プロバイダーの業界も 2000 年代初頭に動き出したが、本格的に花開いたのは数年後だ。Ping Identity(2002)、OneLogin(2009)、Okta(2009)、Duo Security(2010)。これらの企業はほぼすべて SAML プロトコルの上に築かれた。例外は Duo で、同社が最初の SSO 製品を出したのは 2015 年になってからであり、私の話はここから始まる。私は Duo 初のオンプレミス製品 Access Gateway(DAG)の開発に携わった。simpleSAMLphp を土台にした、もちろん SAML プロトコルを土台にした製品だ。そこで私は SAML プロトコルに精通し、その冗長な仕様を消化するために人生の多くの年月を費やした。Kelby Ludwig が XML コメントバイパス脆弱性を見つけたときもその場にいたが、各種の攻撃手法と SAML の欠陥については後で触れる。ひと言でいえば、SSO と認証プロバイダーの業界は当時隆盛を極めており、その大部分が SAML プロトコルの上に築かれていた。
鎧に走った一筋の亀裂
XML 署名ラッピング(XSW)攻撃こそ、SAML のアキレス腱に突き刺さった矢だ。署名ラッピング(2005、2008、2009 年)と SAML(2008 年)を対象としたセキュリティ研究はそれ以前にもあったが、私に言わせればこの分野の嚆矢は「On Breaking SAML: Be Whoever You Want to Be」(2012)だ。理論を実地で検証し、XSW 攻撃を自動検出する手法を生み出した。これが私たちが DAG を実装する際の北極星であり、simpleSAMLphp を土台に選んだ理由でもある。PHP のセキュリティ上の評判は昔から良くなく、当時は特にひどかったが、simpleSAMLphp は例外だった。まだ XSW が何かを知る人がほとんどいなかった時代に、simpleSAMLphp はすでにこの種の攻撃に耐えていた:
simpleSAMLphp のセキュリティ記録(出典:On Breaking SAML)
XSW は 2012 年のあの論文で表沙汰になったにもかかわらず、今も生き残っている。脆弱性の存在が分かっているのに、なぜ直せないのか。ただ、SAML の欠陥を論じる前に、その足元にある頼りない土台、XML を見ておく必要がある。セキュリティ記録の酷さでは XML も負けていない。こうした脆弱性の類型は 90 年代の開発者にはむしろ馴染み深いかもしれないが、今日の XML にもそのまま残っている。XXE、実体拡張(「billion laughs」)、DTD 取得(SSRF)、XPath/XQuery/XInclude/XSLT/CDATA インジェクションなど、枚挙に暇がない。SAML ライブラリはこれらすべての脆弱性に対処してから、ようやく本来の SAML 機能の実装に取りかかれる。セキュリティ上の問題だけでなく、XML は JSON のような形式に比べて純粋に複雑すぎる。XML にはタグ、要素、属性、コメント、名前空間、マークアップと内容の区別、schema、CDATA、DOCTYPE などがある。JSON にあるのは基本的にキー、値、オブジェクト、リストだけだ。複雑さはたいていセキュリティと相反する。SAML が分形構造の悪い設計だと私が考える理由の一つでもある。
悪い設計の分形
SAML にはプロトコル設計を学ぶ機会がふんだんにある。本節では五つの欠陥を論じる。いずれも、認証プロトコルとしての SAML の長期的な実現可能性にとって致命的だと私が考えているものだ。新しい認証プロトコルを設計する際にも参考になる。避けることもできるし、逆手に取ってプロトコルに組み込むこともできる。
XML の上に築かれている
前述のとおり、SAML は XML の上に築かれており、XML は複雑だ。だがそれは委員会の落ち度ではない。当時彼らが手にしていたものであり、人々が使っていたものでもあった。JSON が「発見」されたのは 2001 年だが、ちょうど SAML 委員会が開かれていた時期と重なる。実験的な新形式を軸に認証プロトコルを設計する可能性は低い。ましてや JavaScript に馴染む形式で、書いているのは大量の Java だ。XML と JSON、あるいは SAML と JWT/OIDC の複雑さを定量的に測る尺度(仕様/RFC の語数、仕様/RFC の規定部分の語数など)を設計することはできるだろうが、それには専用のブログ記事か論文が一本必要になる。脱線を避けるためここではやらない。XML は JSON のようなものよりはるかに複雑だとだけ言っておく。
正規化
正規化(C14N)とは、XML のあの混沌を持ってきてハッシュを計算し、一貫した結果を得ようとするときにやる作業だ。言い換えれば、SP と IdP が XML データの一貫した表現で合意できなければ、バイト列が食い違い、署名が一致せず、認証は失敗する。だが、言うは易く行うは難し。正規化の脆弱性は、2018 年の Kelby による XML コメントバイパスの一因となった。
XML 正規化(出典:Identity Theft)
正規化はしばしばパーサー差異や「ラウンドトリップ」脆弱性の前触れとなる。現代の SAML 攻撃の大半はこれらを利用している。
- Go 標準ライブラリにおける XML ラウンドトリップ脆弱性の協調開示(2020)
- Web 全体の XML 実装を保護する(2021)
- libxml2 の癖を利用して GitHub Enterprise の SAML 認証をバイパスする(2025)
- 誰としてでもログイン:パーサー差異で SAML SSO 認証をバイパスする(2025)
- SAML ルーレット:ハッカーが常に勝つ(2025)
- 脆い錠前:SAML 認証の新たなバイパス(2025)
封筒型署名
封筒型署名の問題は正規化と遠からぬ親戚だ。手短に言えば、署名対象のデータペイロードの中に署名を挿入しようとすると、ひどく厄介なことになる。JWT と SAML を次のように比較対照してみよう。
JWT 署名と SAML 署名の比較(画像出典:jwt.io および samltool.io)
上の JWT の例では、青い署名は JSON ペイロードから分離されており、JWT ではピリオド(「.」)で区切られている。SAML の例では、Signature 要素が Assertion 要素の内部に挿入(「封筒化」)されている。問題は、データを同時に改変しているときに、バイト単位で正規化された等価な表現を得るのが難しいことだ。XML のような複雑な形式と複雑な正規化ルールを前にすれば、難易度は上がる一方だ。
「寄せ集め」的な設計
この設計上の欠陥は本質的に「それは要らない」(YAGNI)と同じだ。この言い方はやや不公平かもしれない。過去 20 年で SAML 仕様のうち実際に使われる部分は変わってきたからだ(SOAP と artifact binding には申し訳ない)。だが事実として、現代の SAML 実装の 99% はごく似通ったデータ構造と仕様のごく一部しか使っていない。今日実環境で遭遇する SAML 認証は、まず間違いなく仕様の 90% を迂回している。使われることのない大量の機能のために、かなりの複雑さのコストを払っているのだ。
新しいシステムに SAML サポートを追加するなら、標準的な SAML チェックに加えて、Okta、Onelogin、Google、Shib が生成するメッセージと構造が一致しないメッセージはすべて拒否することを検討するだろう。 —— Thomas Ptacek、2021
硬直化
SAML は別の時代に、別の要求のために設計され、その後、必要な更新がなされないまま今日に至っている。問題は概して理論面ではなく実務面にある。私が硬直化と呼ぶものは、おおむね次のように列挙できる。
- OIDC は HTTP を前提とするが、SAML は転送方式に依存しない。 もちろん SAML にも HTTP バインディングは存在し、最もよく使われる方式ではあるが、必須ではない。これは SAML に一定の柔軟性を与える一方で、その柔軟性を明確に定義し、どこかで実装しなければならず、バグが潜む余地もあるということだ。SAML が生まれた当時、HTTP + TLS はまだ Web サービス通信の絶対的な基盤ではなかったし、SAML はその後の現代的な状況と折り合いをつけないままだ。HTTPS のおかげで、OIDC は暗号化された信頼できる通信をトランスポート層に任せられる。
- OIDC は通常、ネットワークトポロジが連結していることを前提とするが、SAML は前提としない。 最も一般的な OIDC のフロー(認可コード)は、OpenID Provider(OP)と Relying Party(RP)が直接通信できることを前提とする(OIDC の OP/RP は SAML の IdP/SP に当たる)。もちろん、フォーム送信を伴う OIDC のインプリシットフローも存在するが、今日では非常に珍しい。また SAML にも直接通信のための artifact binding があるが、これも同様に非常に珍しい。要点は、OP と RP が直接通信できるなら、認証レスポンスのペイロードに、認証と認可の判断に必要な情報をすべて載せる必要はないということだ。これによりペイロードのサイズと複雑さが減る。OIDC の OP と RP はバックチャネルで情報を交換できる。
- OIDC は長年にわたり有機的に成長してきたのに対し、SAML は基本的に事前に設計された。 OIDC は何年もかけて有機的に成長した数十の仕様と RFC を包含する。これらの文書は通常、特定の要求を解決するために作られたものであり、将来のあらゆる要求を予測して先回りして構築しようとしたものではない。これは第 1 節で述べたアジャイル手法とウォーターフォールモデルの違いに似ている。以下の不完全なタイムラインを見てほしい。OpenID Connect 1.0 仕様の公開(2014)
- JOSE 技術スタックが RFC 7515-7519 を通じて確定し、JW{S,E,K,A,T} をカバー(2015)
- PKCE が RFC 7636 として公開(2015)
- モバイル/ネイティブアプリ向けの PKCE が RFC 8252 として公開(2017)
- IoT デバイス向けのデバイス認可グラントが RFC 8628 として公開(2019)
- MFA ワークフロー向けの Holder-of-Key(DPoP)が RFC 9449 として公開(2023)
- SPA 向けの PKCE が RFC 10017 として公開(2026)
歴史的な背景も興味深い。たとえば SAML は VPN とネットワークセグメンテーションの時代に成熟した。これが上記の第 2 点の由来だ。IdP や SP が企業ファイアウォールの内側にあり、もう一方と直接通信できないと、デプロイ全体が行き詰まり、ベンダーはその受注を失う。SAML はこうした状況をシームレスに処理できなければならなかった。2014 年、Google の BeyondCorp モデルとゼロトラストアーキテクチャがこの考え方を根本から覆した。さらに SAML はモバイル、SPA、IoT の革命を予見しておらず、これらの技術が 2000 年代末に登場したとき、対応策を何も持っていなかった。SAML は企業環境で今も広く採用されているものの、これらのマクロな出来事が相まって、このプロトコルは長く緩やかに衰退してきた。アジリティと疎結合のおかげで、企業は変化し続ける IT 環境に素早く適応できる。
すべての道は OIDC に通じる
完璧なプロトコルは存在しないが、解決策としてはすべての道が OIDC に通じている。私の知る限り、SAML が優位に立つ唯一のデプロイシナリオは、SP と IdP が直接通信できないネットワークだ。OIDC のインプリシットフローとフォーム POST の組み合わせは、まったく同じ要素を提供できる。実際、これは業界で私が見てきた中で最もクリーンな移行策のひとつだ。では、私がサービスプロバイダ(つまり SP)で、SAML を使わずに SSO エコシステムに接続したい場合はどうすればいいか。OIDC をサポートすればいい。SAML は捨てる。どうやら Fly.io と Tailscale はすでにそうしている。
これまでのところ、私たちは OIDC という線を守り続けている。Tailscale も同じだ。Tailscale の顧客が誰かを考えれば、同社が守れているのなら、ほとんどの組織も守れるはずだ。本当に、SAML はできるだけ避けたほうがいい。覚えておいてほしいのは、ベンダーとして競合する相手は、たいてい本物の SSO 統合など何もしていないということだ。 —— Thomas Ptacek、2024
では、私がアイデンティティまたは認証プロバイダ(つまり IdP)で、SAML から抜け出したい場合はどうすればいいか。まあ、顧客の数にもよるが、この道は確かに長いかもしれない。だが、象をどうやって食べるか知っているか。一口ずつだ。これは業界でやり尽くされた道だ。廃止計画を立て、顧客に伝え、新規顧客を SAML 統合に接続するのをやめ、既存の SAML 顧客には同等の OIDC 設定を提供し、終了日を設定して、あとは実行する。SAML は 25 年間輝いた。SSO 業界を生み出し、数え切れないほどの認証を守り、数十の Web サービスでのログインユーザー体験を改善し、数十億ドルの経済的影響を生み出した。SAML プロトコルの作者には感謝すべきだ。テック業界のきわめて激動の時期に、プロトコルがどう設計され、どう進化するかを研究するための絶好の事例を残してくれた。セキュリティ分野の歴史分析をもっと読みたいなら、《Marshal madness: A brief history of Ruby deserialization exploits》を見てほしい。プロトコル設計の監査に関心があるなら、あるいはあなたの認証システムをレビューしてほしいなら、連絡してほしい。