OAuth 2.0 の Implicit grant 終了のお知らせ

f:id:ritou:20181112110600j:plain

おはようございます。 月曜です。 ritouです。

先週、こんな記事出てました。

Why you should stop using the OAuth implicit grant!

ということらしいです。

Implicit grantといえば Token Replace Attack や Covert Redirect など、OAuth 2.0の脆弱性を語る上で欠かせない唯一無二の存在であります。

www.atmarkit.co.jp

私の中では最初から非推奨ですが、公式にとなると気になりますね。

策定中のドキュメントではどう書いているかというと

The implicit grant (response type “token”) and other response types causing the authorization server to issue access tokens in the authorization response are vulnerable to access token leakage and access token replay …

In order to avoid these issues, Clients SHOULD NOT use the implicit grant and any other response type causing the authorization server to issue an access token in the authorization response.

OAuth 2.0 の Implicit Grant では Access Token そのものの値を fragment の値に指定して Authorization Server から Client に戻されます。 その部分で漏洩 / リプレイアタックみたいなやつのリスクがありそうなので、Implicit 使うべきではないみたいな感じですね。

この記事における理由としては

  • Implicit Grant のセキュリティは修理不可能なほどぶっ壊れている
    • トークン漏洩に脆弱で、攻撃者は取得した Access Token で 色々できる
  • Access Token の悪意ある再利用を防ぐためには、sender constrained access token が必要
    • このトークンタイプをサポートするために Implicit grant を拡張することは容易でない

となっていて、なるほど詰んでる。って感じです。

続いて、これはOAuth 2.0にとって致命傷となるか?については

  • もともと Implicit = Browser-based JavaScript App onlyではなかった
    • Authorization Code Grant はいいぞ

と、AuthZ Code 推しとなっています。これもわかる。いわゆる、わかりみがある。

ではなぜ、Implicit grant があるのかってとこで...ちょっと引っかかりました。原文のまま見ていきます。

Well, in the old days (back in 2010) browser-based apps were restricted to sending requests to their server’s origin only.

むかーしむかし、ブラウザベースのアプリはリクエストの送信を自分たちのサーバーの origin に制限されていました。

So there was no way to call an authorization server’s token endpoint at a different host.

なので、異なる host から AuthZ Server のトークンエンドポイントを呼び出す方法がなかった。(?)

That’s why the short cut was introduced to deliver the access token in the authorization response through the browser.

それがショートカットで AuthZ Response 内に Access Token を含んで渡す理由だ(??)

The risks associated with this approach should be mitigated by limiting the privileges and lifetime of such tokens. The implicit grant has always been a compromise!

Access Token の権限やライフタイムを制限することでリスクを緩和するしかなかった。みたいな。

この説明について、そもそも AuthZ Server のエンドポイントを叩けないならば、Implicit grant で Access Token をわたしたって Resource Server のエンドポイント叩けるんですか? AuthZ Server だけ制限しているケースってあるの?みたいな気持ちになりました。

そんなのよりも、Access Token をフラグメントで渡す理由は

  • ブラウザベースのアプリケーションは Public Client であり、 Client Secret を安全に管理できない
  • Authorization Code Grant でもユーザー/攻撃者から簡単に取得できる Client IDだけで Access Token に交換できる
  • 最初から Access Token 渡せばいいじゃん。アプリをホストしているサーバーに値が渡されたくないならフラグメントで

ぐらいな感じじゃないのかと思っておりました。今も思っています。

記事ではここから CORS 万歳!みたいになります。

Thanks to Cross-Origin Resource Sharing (CORS) this compromise now ends. CORS allows browser-based apps to send requests to hosts outside of their origin given the destination permits it.

And what’s very important, it’s broadly adopted! This evolution allows the OAuth working group now to recommend use of the authorization code grant for browser-based apps, that way leveraging the aforementioned security benefits to those apps as well.

CORS 使って AuthZ Code Grant でやるのを推してく!みたいに書いてあります。

まだ残る CORS 推しの違和感を解消するため、別の記事で、こんなの見つけました。

What is the OAuth 2.0 Implicit Grant Type?

この記事では、Implicitが今の仕様になった経緯が "When to use the Implicit Grant Type" のところで説明されています。

One of the historical reasons that the Implicit flow used the URL fragment is that browsers could manipulate the fragment part of the URL without triggering a page reload. However, the History API now means that browsers can update the full path and query string of the URL without a page reload, so this is no longer an advantage of the Implicit flow.

ページのリロードなしでフラグメントの値を操作できるので便利たったけど History API で戻ったりできるようになったのでそんなにアドバンテージではないってのと、

The one remaining reason to use the Implicit flow is if the authorization server doesn’t or can’t support cross-origin requests (CORS). The Authorization Code grant requires that the JavaScript app make a POST request to the authorization server, so the authorization server will need to support the appropriate CORS headers in order to allow the browser to make that request. This is a relatively easy change to make if you’re building your own authorization server, but if you are using an existing server then you may be stuck using the Implicit grant to get around the CORS limitation.

AuthZ Server が CORS 対応してない or できない場合には既存の Implicit Grant で回避するしかなかったみたいなのが書いてあります。 この説明であれば少し親切かもしれません。が、これが決め手とはどうしても思えないですね。

では今後どうすれば良いかについて、Draftが出ています。

draft-parecki-oauth-browser-based-apps-00 - OAuth 2.0 for Browser-Based Apps

00なので今はじっくり見てませんが、落とし所としては

  • PKCE : Public Client でも sender constrained な仕組みにできる
  • Response Mode : AuthZ Code Grant でもフラグメントに載せられる

の併用あたりになるのではと予想しています。

違和感を覚えても安易に「いい加減なこと書いてるとぬっCORSぞ」みたいなことは言わずに、ベストプラクティスを追求していきたいですね。

ではまた。