Office 365 SAML Implementation Vulnerability

先日 Office 365 のこんな記事見つけたので、一応まとめておきますかね。

The road to hell is paved with SAML Assertions

タイトルだけ見るとまた SAML is DEAD 案件かと思いきや、Office 365 の脆弱性の話です。

SAML 悪く無いです。

SAML isn’t vulnerable, just DEAD.

SAML SP としての Office 365

Office 365 は SAML Service Provider (SP) として動作するので、みなさんがお持ちの Identity Provider (IdP) を SAML IdP として動作することができれば、みなさんの IdP に登録されてるアカウントを使って Office 365 にログインすることができます。

みなさんの社内の ADFS とか、Ping Federate / Okta / OneLogin … みたいな IDaaS とか、そういうのは大抵 SAML IdP として動作するので、そういう製品を使ってるなら、みなさんの会社のアカウントでそのまま Office 365 にログインできます。

通常 SAML SP は、IdP から返ってくる SAML Response に含まれる IdP 側のユーザー識別子 (Subject Identifier) と IdP 自身の識別子 (Issuer Identifier) のペアを元に、SP 側のアカウントにログインさせます。

がしかし、Office 365 の場合は、IdP が渡してくる Email アドレスと Office 365 がローカルで持ってる Email アドレスの一致だけを見て Office 365 ローカルのユーザーを認証していたようです。Subject Identifier も Issuer Identifier も無視していた、と。

(実際には、SAML IdP と Office 365 の間に Azure AD が介在しており、SAML Assertion の検証は Azure ADがやるようなアーキテクチャになっていて、Azure AD では Subject Identifier & Issuer Identifier をちゃんと見ているようですが、全体として見ると Office 365 が SAML IdP の Issuer と Subject をガン無視した形になってます。この辺の話しだすとややこしい割に MS 以外の人にはあまり関係無い話になっちゃうので、今回はスルー)

Office 365 の脆弱性概要

これで何が起こっていたかというと、nov@victim.example.com という Email アドレスを持つ Office 365 ユーザーのアカウントにログインする際に、attacker.example.com という IdP が nov@victim.example.com という Email アドレスを含んだ SAML Assertion を発行すると、Office 365 がその Assertion を受け入れて nov@victim.example.com の Office 365 アカウントへのログインを許可してしまっていました。

よって、以下の2つのパターンが、どちらも同じ Office 365 アカウントにログイン可能になっていました。

Issuer Identifier Subject Identifier Email Address
attacker.example.com 58df3c9b2c32ca86f.. nov@victim.example.com
victim.example.com 20166f0c077c1f6c1.. nov@victim.example.com

うん、これは最悪ですね。

Consumer の世界に置き換えると、つまりどういうこと?

Consumer 分野であれば、Facebook と Google の両方を IdP として使う RP がいる場合、Facebook が返すユーザーの Email アドレスが Gmail だったりすることは普通にあります。

この時、Facebook が nov@gmail.com というメアドを返してきた場合に、RP 側で nov@gmail.com というメアドを持つユーザーを、たとえそのアカウントが Facebook アカウントと紐付いていない状況だったとしても認証してしまう、と、Office 365 がやっていたのは、そういう処理です。

Facebook と Google だけが IdP であれば、どちらも Email 疎通確認等をちゃんとしているという前提があるため、以下の2つの Identity は同一人物に紐づくという前提で設計することもできるでしょう。

Issuer Identifier Subject Identifier Email Address
google.com 58df3c9b2c32ca86f.. nov@gmail.com
facebook.com 58df3c9b2c32ca86f.. nov@gmail.com

しかし、OpenID 2.0 の頃のように、ユーザーが Dynamic に任意の IdP を選択できるとしたらどうでしょう?

以下の3つめのアカウントが、その上の2つと同一人物に紐づくという前提条件は、あっさり崩れてしまいます。

Issuer Identifier Subject Identifier Email Address
google.com 58df3c9b2c32ca86f.. nov@gmail.com
facebook.com 58df3c9b2c32ca86f.. nov@gmail.com
attacker.example.com 58df3c9b2c32ca86f.. nov@gmail.com

Office 365 の場合、テナントごとに任意の IdP を指定することができるため、攻撃者が Office 365 にテナント登録してしまいさえすれば、attacker.example.com を IdP として登録できてしまい、上記の3つめのパターンを作り出すことができてしまいます。

そして、OpenID Connect でも「OAuth 認証」でも、同じような脆弱性は発生しそうですね。

SAMLer 以外のみなさんも、気をつけないとですね。

こういう場合、どうすればいいの?

まずは基本的には、以下3つのパターンが RP 側では全て異なるアカウントに紐づくように設計することです。

つまり、Subject Identifier と Issuer Identifier のペアごとに、異なるアカウントに紐づくようにする、と。

Issuer Identifier Subject Identifier Email Address
google.com 58df3c9b2c32ca86f.. nov@gmail.com
facebook.com 58df3c9b2c32ca86f.. nov@gmail.com
attacker.example.com 58df3c9b2c32ca86f.. nov@gmail.com

その上で、RP 側で Email アドレスがユニークである必要があるのであれば、3つのアカウントを RP 側で一つのアカウントに紐付けるためのフローを RP が頑張って実装するか、IdP から渡される Email アドレスを無視して別の Email アドレスを設定させる等の処理が必要です。

そのあたりの細かい実装方法については… YAuth.jp に相談?w

Office 365 はどういう修正をしたのか?

これは、元記事にも書いて無いですね。

でも7時間で修正されたって書いてあるので、上記のような解決策ではなくて、以下の1つめのパターンを reject するようにしたのでしょう。

Issuer Identifier Subject Identifier Email Address
attacker.example.com 58df3c9b2c32ca86f.. nov@victim.example.com
victim.example.com 58df3c9b2c32ca86f.. nov@victim.example.com

要するに Issuer チェックをするようにしたんでしょうが、SAML IdP と Office 365 の間に Azure AD がいるっていう状態で、具体的にどの箇所でどういう検証をするようにしたのかってのは、よくわからず。

Office 365 の MVP の人とかに聞くとわかるんですかね、こういうのは?

ps. 本記事執筆にあたっては、腹違いの兄さんことふぁらおう兄さんに長時間にわたって相談に乗っていただきました。にいさん、いつもありがとうございます!

Comments