しばらく前に世間を騒がせたOffice365のSAML SP実装に関する脆弱性の話が色々と解説されているので、ちょっと動きを細かく見ていきたいと思います。
騒動の元ネタ
The road to hell is paved with SAML Assertions
http://www.economyofmechanism.com/office365-authbypass.html
OAuth.jpでのnov氏による解説記事
Office 365 SAML Implementation Vulnerability
http://oauth.jp/blog/2016/05/14/office-365-saml-implementation-vulnerability/
John Bradley氏による解説
Azure AD security issue
http://www.thread-safe.com/2016/05/azure-ad-security-issue.html
Internet2での解説
Scoped User Identifiers
https://spaces.internet2.edu/display/InCFederation/2016/05/08/Scoped+User+Identifiers
まぁ、起きていた事象と根本的な原因はIdPが発行したクレームを無条件に信じてしまっていたことにより他のテナントのユーザになりすましてしまうことが出来たよ、ということなので、ちゃんとVerifyしようよ、という話になっています。
◆何が起きていたのか再現してみる
と、言ってもすでにOffice365の脆弱性は修正済みなので、起きていたであろうことをAD FSとGoogle Appsを使って再現してみました。AttackerとVictimの2つのIdPをAzure ADが収容して、共通のアプリケーションを利用する、という構図をGoogle AppsとAD FSを使って再現したのが以下の図のようなシステム構成になります。
Azure AD相当のAD FSが各IdPから渡ってきたEmailアドレスをストレートにNameIDに変換してアプリケーション(Google Apps)へ渡してしまうので、VictimにもAttackerにも同じメールアドレスのユーザが存在するとAttackerもGoogle Appsへログインできてしまいます。
(もちろん実際のOffice365/Azure ADではもう少し複雑な動きのはずですが、解説のためものすごく簡略化しています)
◆実際の動作
まず、各IdPに同じメールアドレスを持ったユーザを作成します。これは簡単ですね。Active Directoryのユーザとコンピュータからユーザのメールアドレス属性を編集してあげるだけです。この状態でGoogle AppsへアクセスするとAzure ADに相当するAD FS(今回はHUBと呼びます)へリダイレクトされ、IdPの選択をするホームレルムディスカバリ画面が表示されます。これは、Office365の場合、メールアドレスのドメインパートで自動的に振り分けるような仕組みになっていますよね。
まずは正常系です。
ここでvictimを選択するとvictim側のAD FSへ再度リダイレクトされ、victim側のユーザでの認証が行われます。
もちろんここでログインすると問題なくGoogle Appsへアクセスできます。
今度は先ほどのIdP選択画面でattackerを選択してみましょう。
同じくattackerのログイン画面が表示されるので、attackerのユーザでログインしてみます。
すると、意図しないユーザであるにも関わらずGoogle Appsへのログインができてしまいます。
右上のユーザ名を見るとvictimのユーザとしてログインできていることがわかります。
これが問題です。
◆構成を見てみる
では、この環境がどのように構成されているのか見ていきましょう。まずはHUBとなるAD FSの構成です。
Relying Partyには当然Google Appsが構成されています。
HUBとなっているので、IdPから渡ってくるEmailアドレス属性をNameIDへマッピングして出力を行うクレーム・ルールが設定されています。
次に、HUBのIdP(Claim Provider)設定を見てみます。マルチテナントで構成されているので当然victimおよびattackerがIdPとして登録されています。
そして、各IdPのクレーム・ルールを見ると単純に各IdPから渡ってくるEmailアドレスをパススルーしています。ここが大きな問題です。
取り敢えず問題は置いておいて、次に行きます。
次は各IdP側のRP設定を見ていきます。
当然、victim側にもattacker側にもRPとしてHUBが登録されています。
こちらがvictim側です。
こちらがattacker側です。
この辺りは特に不思議なところはありません。
クレーム・ルールも共通で以下の通り、ADのEmailアドレスをそのまま発行しています。
構成はこれで終わりです。
次はSAML Tracerを使って動きを見てみます。
◆SAML Assertionの中身の確認
まず、正常パターンです。victimで認証されてSAML ResponseがHUBへ返ります。属性ステートメントにメールアドレス属性が正しく入っていることがわかります。
同様にattackerも見てみます。
先のルールだとattackerからもメールアドレス属性をそのまま発行することになるので、HUBへのSAML Responseにはメールアドレスが入ります。これは正常な動きです。
では、attackerからのResponseを受けたHUBがGoogle Appsへ返すSAML Responseを見てみます。
いけませんね。NameIDにvictimのメールアドレスが入ってしまっています。
Google Appsから見るとこのResponseはあくまでHUBから返ってきており、AssertionのIssuer(HUB)および署名(HUBのAD FS Token Sign)の検証が出来てしまうので、正しいAssertionだと認識してしまい、ログインが完了してしまいます。
◆どうやってなりすましを防ぐか?
では、ここからが対策です。要するにHUBが配下のIdPから飛んでくるクレームを無条件に上位のアプリケーションへ発行してしまっているのが問題なので、フィルタリングを入れておきたいと思います。
具体的には、victimから飛んでくるメールアドレスはvictimの、attackerから飛んでくるメールアドレスはattackerの固有のドメインパートを持っている、という暗黙の前提の通りになっているかどうか?を確認し、正しければスルーしますし、異なっていたらフィルタリングしてしまいます。
AD FSにおいて、この設定はClaim Providerのクレーム・ルール設定で行います。
以下がvictim側の設定です。
次にattacker側の設定です。
この状態における実際のAssertionはどうなっているでしょうか?
まずは正常系(victim)です。メールアドレスがvictimorg.xyzで終わっているのでスルーされてAssertionに値が入ります。
しかし、attacker側ではメールアドレスがattackerorg.xyzで終わることが期待されるところにvictimorg.xyzが入ってきているのでフィルタされ、Assertionに値が入りません。
こうなるとGoogle Appsへのログインは失敗し、なりすましはできなくなりました。
◆対策とまとめ
結局のところは、「外部のIdPとフェデレーションを行う際はIdPの信頼性の担保が出来ているかどうかを確認すべし!」という話なんですが、「じゃあ、どうやって?」というところで例えばメールアドレスを使うOffice365やGoogle Appsなんかの場合は、暗黙の前提となっているドメインパートに正しい値が入ってくるであろう、という部分を排除してきっちりとフィルタリングをするという対策が必要になりますし、他の属性を使う場合でも、その属性に入ってくる値は当該のIdPで正しさが保証されているものなのか?を中間IdPやRP側でも確認をすることは必須である、ということが出来ます。オンプレミスのActive Directoryの信頼関係でも同じですが、技術的につながるからと言って無条件につなぐと当然セキュリティ・ホールが出来上がるので、文字通り「信頼」をするためには必要な対策をちゃんとしましょう、ということです。
また、これはSAMLでもws-federationでもOpenID Connectでも全く同じことですので、うちのサービスはSAMLじゃないから大丈夫、と言ってスルーしないでください。
参考までに、ですがAD FSでは外部IdPから発行されたクレームを無条件にパススルーしようとすると以下のワーニングが表示されます。
ワーニングにはちゃんと意味があるので、みなさん従いましょうね。
0 件のコメント:
コメントを投稿