OAuth 2.0 で Resource Owner Password Credentials が非推奨なのはなぜなのか
OAuth 2.0 で Resource Owner Password Credentials が非推奨なのはなぜなのか
OAuth 2.0 Security Best Current Practice という OAuth 2.0 のベストプラクティスの公式ドキュメントがあって、このなかで OAuth 2.0 のフローのうち Implicit Grant は SHOULD NOT に、Resource Owner Password Credentials Grant は MUST NOT となっています。
もちろん、最も一般的な Authorization Code Grant と比べると、次のように生パスワードを送信する Resource Owner Password Credentials Grant は危ないんだろうなあという感覚はありました。
POST https://example.com/auth2/token
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=taro&password=P@ssw0rd
しかし、使うな! レベルなのは腑に落ちなかったので調べました。このドキュメントは私見です
OAuth 2.0 ややこしい!
OAuth 2.0 / OpenID Connect を初めて触ったときに感じたのはそのややこしさでした。アプリケーションが Rails のようなバックエンドのものとフロントエンドでフローが全然違う、リクエストはクエリだったりフォームデータだったり JSON だったりで渡し、レスポンスも JSON なこともあればクエリなこともあります。手順通りにやれば動きはするのですが、なんでこんなややこしいことになっているんだろうとキレながらりようしていました。
それが様々なアプリケーションのスタイル (バックエンドだとかフロントエンドだとかもろもろ) がそれぞれ安全になるように設計されていると分かってからはキレることはなくなりました。今では、よく考えられていて頭がいい人たちはやっぱり違うなあと思っています。
理由と思われるもの
アプリケーションを特定できない
メールを読む際には、POP3 や IMAP4 を利用して、メーラーと呼ばれるアプリケーションにパスワードを設定することも多いです。この方法はアプリケーションがユーザーのパスワードを知ることになります。開発者はユーザーのパスワードを取得できるようにメーラーを開発することができます。悪意のある開発者はこれを利用するでしょう。
Resource Owner Password Credentials Grant も直接アプリケーションがパスワードを扱うので同様です。
もちろん、Rails のようなバックエンドアプリケーションであれば client_id
と client_secret
を発行することで、アプリケーションごとに許可が出せます。問題が発生した場合にそのアプリケーションに対しての許可を取り消すことができます。
しかし、モバイルやデスクトップのアプリケーションおよびフロントエンドアプリケーションは安全に client_secret
を保持することができません。悪意のあると分かったアプリケーションを止めることは困難です。
代わりに Authorization Code Flow を使います。PKCE とリダイレクト URL でアプリケーションを特定することができます。(Android ではアプリリンク、iOS では Universal Link を利用します)
パスワードを扱う個所を減らしたい
Resource Owner Password Credentials Grant では、アプリケーションもパスワードを扱います。このアプリケーションが安全にパスワードを扱えているかはアプリケーションの開発者にかかっています。
パスワードを安全に扱うことはかなり難しく、しかもサイバー攻撃の進化に合わせて継続した対策も必要です。基本フレームワークに任せでいいのですが、フレームワークを使えば確実に安全になるわけでもないので、何も調べない知らない考えないではすみません。
サードパーティアプリケーションが安全にパスワードを取り扱ってくれるかという問題もありますが、自社サービスのウェブ版とモバイル版というアプリケーションであっても、パスワードを両方で扱うのは開発者の負担になります。(パスワードだから安全でしょっていう人たちにとってはどうでもいいんでしょうけど、自分はめんどくさいです) ウェブ版だけがパスワードを扱うようにした方が開発が楽になります。
フィッシング対策
Resource Owner Password Credentials Grant では、各アプリケーションごとにパスワードを入力するスタイルになります。
例えば、Amazon のウェブサイトであれば、利用者はドメインと HTTPS だということが確認できれば公式のものだということが分かり、フィッシングではないことを確認できます。しかし、モバイルの Kindle アプリではログイン時にパスワードの入力が求められますが、起動したものが Amazon 公式の Kindle アプリかを利用者が確かめることはかなり難しく、フィッシングではないことを確認することができません。
Kindle アプリのように、公式かどうかが分からない状態でパスワードを入力するのが当たり前になってしまうと、利用者はフィッシングアプリかどうかを確かめずにパスワードを入力することになります。これは避けたいところです。
確かに、最近はモバイルアプリやデスクトップアプリでも、ログインは公式ウェブサイトに遷移して行うタイプが増えています。
多要素認証やパスキーの存在
パスワードは漏洩することは稀なのですが、漏れた影響はかなり大きなものとなります。そこでパスワードのほかにワンタイムパスワードなども併せて利用する多要素認証があります。また、パスワードそのものを不要にするパスキーがあります。
Resource Owner Password Credentials Grant はこれらに対応していません。対応させることは可能でしょうけど、今後様々な攻撃方法が編み出さるとそのたびに対策を規格に織り込まなければなりません。WebAuthn のように追加するのが難しいものもあります。
Authorization Code Flow であればどのような方法で認証するかは OAuth 2.x の範疇外になります。その時代時代に合わせたベストのものが利用できます。
そもそも Resource Owner Password Crdentials Grant は特殊
今にして思えば Resource Owner Password Credentials Grant はかなり特殊です。認証をパスワードにするのかとか顔認証にするのかとかいった話は、本来 OAuth 2.x 規格の責任外なはずなんですよね。なぜかパスワード認証に限定した規格があったわけです。
OAuth 2.1 からは Resource Owner Password Credentials Grant は廃止されるようなので、おかしな状態から脱却できるわけです。
結論
Resource Owner Password Credentials Grant が廃止になる理由はだいぶわかりました。(分かった気になってるだけかもしれませんが) これに限らず、OAuth 2.0 規格策定して実際に運用してみてわかった問題もたくさんあるようで、ベストプラクティスはそれを反映しています。
自分一人では安全になるのはどうしたらいいかの結論を出すことは困難です。今回調べてみて大体は納得できました。でも、考え違いをしているところもまだまだあるでしょう。それでもベストプラクティスやそれを反映したフレームワークに従えば安全性を担保できるのはとてもありがたいです。
たとえ OAuth 2.x を利用しなくても、認証や認可で対策しないといけない脅威は変わりませんので、とても参考になります。
規格やベストプラクティスを作って、それらを改訂し続けている関係者の方々に感謝。
Discussion