OAuthの認可コードはなぜ必要なのか

OAuth初心者ですさん  
(No.1)
認可コードが必要な理由がわかりません。

よくネットに書かれているOAuthの流れです

1.リソースオーナーが認可サーバで認証成功する
2.リダイレクトで認可コードがクライアントに渡る
3.クライアントが認可コードを添えて認可サーバへアクセストークンを要求する
4.認可サーバからクライアントへアクセストークンを渡す

上の2と3、いらないと思っています。
下じゃダメなんですか?

1.リソースオーナーが認可サーバで認証成功する
2.クライアントから認可サーバへアクセストークンを要求する
3.認可サーバからクライアントへアクセストークンを渡す


リソースオーナーが認証に成功したら、認可コードを受け取るのではなくて、クライアントが認可サーバに対してアクセストークンを要求すればいいのに。と思います。
認可サーバ側には特定のクライアントIDが認証成功した情報が残っているはずで、わざわざ認可コードを経由する理由がわかりません。

どなたか教えていただけないでしょうか。
2024.10.02 22:03
tinyfinさん 
(No.2)
私は詳しくはないのですが、興味があり少し調べました。

認可コードを介さず直接アクセストークンを渡す手法は存在し、今は非推奨のようです。

未熟故私の口から解説することはまだ困難ですが、「インプリシットフロー」や、「RFC 6749, 4.2. Implicit Grant」で調べてみてください。とても興味深い内容が出てきます。
2024.10.02 22:46
たけしさん 
(No.3)
ネットや書籍で得た知識で宜しければ共有いたします。
認可コード自体は予測困難なランダム値ですが
認可サーバがクライアントを識別するための「クライアントID」等が紐づけられています
このクライアントIDはクライアントから認可サーバへの「認可リクエスト」に含まれます。
この認可コードが無いと、トークン発行時にクライアントの識別ができなくなるため
トークンの横取りが可能となってしまいます
tinyfinさんの「インプリシットフロー」は現在使うべきではないとされているのですが
その理由が認可コードを発行しない = 発行したトークンを渡す相手を確認していないから
と私は理解しております。
2024.10.02 23:26
OAuth初心者ですさん  
(No.4)
ご回答ありがとうございます!

>インプリシットフローが非推奨の理由が
認可コードを発行しない = 発行したトークンを渡す相手を確認していないから

発行したトークンを渡す相手の確認は、認可コードではなく、クライアントIDで行えばいいんじゃないでしょうか?

リソースオーナーによる認証を終えた後、認可サーバには「①認証結果」と「②認可リクエストに添えたクライアントID」の情報があるわけですよね。

じゃあ認可コードなんて発行してもらわなくても、
クライアントが認可サーバに対して、クライアントIDを添えて「アクセストークンをください」と要求すれば、認可サーバは手元の①②をみてアクセストークンを払い出せますよね。

なぜ必要なんでしょうか。


とここまで書いてふと思ったのですが、
この仕組みだとクライアントIDを偽造して総当たり攻撃をされると悪意のある第三者にトークン奪取されそうですね。

やっぱり認可コードは必要なんですね...
2024.10.02 23:51
たけしさん 
(No.5)
実は私も以前スレ主様と似たような疑問を持って
OAuth関連の書籍(KeyCloakのやつ)を以前立ち読みしてみたのですが
読めば読むほど結構深い内容で頭がパンクしそうになったのを覚えてます...
なので、自分なりに嚙み砕いて上記の様に理解した次第です
ちなみに認可コードにはクライアントID以外にも様々な情報と紐づけられているので
より深い理解をしたいのであれば、検索してみても結構情報はあるので
ご自身で調査するのが宜しいかと思われます。

拙い内容でしたが、ご参考になれば幸いです
2024.10.03 00:32
X8bWwさん 
(No.6)
この投稿は投稿者により削除されました。(2024.10.04 11:59)
2024.10.04 11:59
X8bWwさん 
(No.7)
OAuth2とOpenID Connectを何度か実装したことがある者です。

自分で読み返してちょっと微妙だったので修正投稿しました。

全く調べずに書いているので、正確性に欠くかもしれませんが、参考になれば

前提

1. OAuth2でいうクライアントIDは公開情報です
ただの識別子で、秘密情報として扱いません。
リソースオーナーをリダイレクトする際にクライアントIDをURLに含めますから、秘密でないのは当たり前ですね。

2. クライアント認証に使うのはクライアントシークレットです
これはクライアントが秘密にしなければなりません。
クライアントIDと合わせることで、クライアントとして認証するときに使います。
これには十分な長さを持たせますから、総当たり攻撃のことは考慮しなくて大丈夫です。(それを考慮したらパスワードという概念が消滅してしまう)

シナリオ1. クライアントはクライアントシークレットを秘密に出来るとは限りません
例えば、ネイティブアプリケーションを想定してください。
クライアントIDは、クライアントの種類ごとに付与しますから、同じネイティブアプリケーションは同じクライアントID/シークレットを使用します。
ユーザーに配布するアプリケーション自身がOAuth2でtokenを取得するのですから、質問者さんの提案する流れだと、クライアントシークレットもユーザーに配布することになります。
これでは通信に中間者攻撃したりリバースエンジニアリングしたりでユーザーがクライアントシークレットを取り出せてしまいます。
こういうクライアントシークレットを安全に保持できないクライアントを、Public Clientといいます。
こういったケースでは、「そのクライアント(の種類)であること」ではなく、「リソースオーナーの手元で動いているクライアントであること」を証明する必要があり、これに認可コードを用います。
認可コードフローの場合、こういったクライアントはクライアントシークレットなしで認可コードだけでトークンを取得できる場合が多いです(認可サーバーによります)。

シナリオ2. クライアントからみたユーザーは複数いる
Webアプリケーションなど、クライアントシークレットを安全に保持できる場合を考えます。
提案された流れだと、クライアントを使っているユーザーが複数いないことを前提としています。
同時に複数人が利用した場合、認可サーバーはどのユーザーのトークンを返せばいいのか分からなくなります。
例えば、AさんとBさんが同時に認可サーバーでの処理を済ませたとき、クライアントがトークンを要求すると2つのトークンを受け取ることになりますが、どちらがAさんのトークンでどちらがBさんのトークンか分かりません。
この対策としては、認可サーバーにリダイレクトするときに識別子を付与するというのが考えられます。しかしこうした場合、攻撃者がリダイレクト先URLを他のユーザーに送って、そのユーザーがクリックして認証を行ったとき、攻撃者のクライアントのセッションに被害者のトークンが紐づくことになってしまいます。

まとめ. 利用者は複数いる
どちらのシナリオにも共通するのは、クライアントの利用者が複数いるという点です。
この点に気をつけて考えれば、認可コードが必要な理由は見えてくるのではないでしょうか。
どの利用者なのかを識別するという観点を持ちましょう。

補足
質問者さんの提示している流れはImplicit Flowではありません。
Implicit Flowはリダイレクトで認可コードではなくトークンを渡すというものです。
質問者さんの流れの場合、そもそもリダイレクトで何も渡さないという事になるので全く異なります。
ちなみに、Implicit Flowではトークンがユーザーに見えてしまったり閲覧履歴に残ってしまったりするという問題があります。(認可コードなら1回使い捨てで普通は即座に使用されるので問題ない)
2024.10.04 12:01
tinyfinさん 
(No.8)
X8bWwさん。ご指摘ありがとうございます。
やはり私の認識は誤りがあったようですね。申し訳ないです。
2024.10.04 18:35
Oauth初心者ですさん 
(No.9)
ありがとうございます!
シナリオ1.シナリオ2に関して仰るとおりですね。

>Implicit Flowではトークンがユーザーに見えてしまったり閲覧履歴に残ってしまったりするという問題があります。
たしかに、認可コードフローだとユーザーの元にトークンが渡らないですね!勉強になりました!!
2024.10.06 01:11

返信投稿用フォーム

スパム防止のためにスレッド作成日から30日経過したスレッドへの投稿はできません。

その他のスレッド


Pagetop