今月(2018年10月)のはじめに突如アナウンスされた「Azure ADのOAuth2.0におけるAuthorization Codeの再利用禁止」について現状を確認してみます。
というか、まさか認可コードが再利用できるとは思っていなかったので、アナウンスされるまで気が付きませんでした・・・。
アナウンス
https://blogs.technet.microsoft.com/jpazureid/2018/10/04/authorization-code-reuse/
リリースノート
https://docs.microsoft.com/ja-jp/azure/active-directory/fundamentals/whats-new#change-notice-authorization-codes-will-no-longer-be-available-for-reuse
◆アナウンスされた内容
詳しくは上記リンクを見て頂ければと思いますが、ざっくり言うと以下の事項がアナウンスされました。- 従来はAzure ADのOAuth2.0/Code Flowで認可エンドポイントから発行される認可コード(Authorization Code。MSの日本語訳だと「承認コード」)の再利用が出来てしまう状態だった
- RFC 6749に準拠するため、認可コードの再利用を禁止することにした
- 新たなポリシーはv1/v2の両方のエンドポイントに対して適用される
- 新たなポリシーの適用は2018年10月10日から開始される
- ポリシー適用後は認可コードを再利用しようとすると「invalid_grant」エラーが出るので、アクセストークンを取得し直す場合はリフレッシュトークンを利用するように既存のコードを修正すること
◆RFC 6749における認可コードの取り扱い
RFC 6749をみると、認可コードの取り扱いは以下の様に記載されています。- 認可コードは認可サーバーによって許可される. 漏洩のリスクを軽減するため, 認可コードは発行されてから短期間で無効にしなければならない (MUST)
- 認可コードの有効期限は最大でも10分を推奨する (RECOMMENDED)
- クライアントは2回以上認可コードを使用してはならない (MUST NOT)
- もし認可コードが2回以上使用された場合は, 認可サーバーはリクエストを拒否しなければならず (MUST)
- この認可コードを基に発行されたこれまでのすべてのトークンを無効化すべきである (SHOULD)
- 認可コードはクライアント識別子とリダイレクトURIに紐づく.
出典)OpenIDファウンデーション・ジャパン翻訳WG
https://openid-foundation-japan.github.io/rfc6749.ja.html#code-authz-resp
この3~5番目のあたりですね。
なお、RFCにおけるMUST NOT(してはならない)の定義は「この語句、もしくは「することはない( SHALL NOT )」は、その規定が当該仕様の絶対的な禁止事項であることを意味します。」となっています。(強調は筆者による)
出典)IPA翻訳:RFC において要請の程度を示すために用いるキーワード
https://www.ipa.go.jp/security/rfc/RFC2119JA.html
・・・
「絶対的な禁止事項」って明確に書いてあるのに無視したんですね。
マイクロソフトのアナウンスを見ると、以下の注釈が付いていますので、よく理解せずに実装をしてしまったアプリへの配慮があったということなんだとは思いますが。
「アプリの破損を最小限に抑えるための試みにおいて、このパターンに依存していて、サインインが 1 日 10 回より多いアプリには、例外が与えられてきました。」
ちなみに、同じくRECOMMENDEDになっている2番の認可コードの有効期限はAzure ADでは15分です。
こちらもRFC的な意味合いを見ると「この語句もしくは「推奨される( RECOMMENDED )」という形容表現は、 特定の状況下では、特定の項目を無視する正当な理由が存在するかもしれませんが、 異なる選択をする前に、当該項目の示唆するところを十分に理解し、 慎重に重要性を判断しなければならない、ということを意味します。」(同じく強調は筆者による)とあるので、ちゃんと正当な理由の存在をもって慎重に重要性を判断したんだと信じたいところです。
15分になっている理由として、アナウンスの中の別の文章を見ると、「従来は 15 分間 (10 分間の有効期限に加えて時刻ずれを考慮して 5 分の猶予が与えられている) 有効です」とあります。時刻ずれを考慮したんですね。
ちょっと待て。。。発行から15分という話なら時刻ずれ関係なくないか?認可コードの中にタイムスタンプが埋め込まれている?唯一、Azure AD B2Cが発行する認可コードがJWTっぽいのでデコードしてみましたが、ペイロードがなくタイムスタンプ情報が入っているようには見えないんですが・・・。それとも認可エンドポイントとトークンエンドポイントが別のサーバで動いていて時刻同期がされていない、ということ?うーむ。
◆取り敢えず動作の確認
アナウンスでは10月10日から動作が変わる、ということだったので10月4日の段階で動作を確認してみました。対象は、v1/v2/B2Cの3パターンです。
v1/v2はChrome ExtensionのAdvanced REST Clientで認可コードをトークンエンドポイントへ何度投げ込んでもIDトークン、アクセストークン、リフレッシュトークンが返ってきます。
15分経過すると有効期限切れのエラーが出ます。10分か15分かは置いておいてこちらは正しい挙動ですね。
尚、Azure AD B2Cの場合はAdvanced REST Clientだと上手く動かないことがあるので(Client Secretに記号が含まれることが多いから?)、Postmanを使って動作確認をします。
ツールは違えど、v1/v2と同じ動きです。
◆10月10日を超えたらどうなったのか?
ということで本題です。10月10日を超えたので、どのような動きになったのか確認してみましょう。
結論から言いますと、アナウンス通りに認可コードの再利用が禁止されたのはv2エンドポイントだけでした。v1とAzure AD B2Cでは相変わらず認可コードが再利用できてしまいました。何か事情があったんでしょうか。。。
以下、v2エンドポイントで認可コードを再利用した際に出るエラーです。
「OAuth2 Authorization code was already redeemed」ってあるので、ちゃんと再利用だと判断されているようです。
いずれにしても認可コードの再利用を前提としたコードがあれば早めに書き直しましょう。v1/B2Cもそのうち再利用禁止になると思いますので。