「暗黙的」フローがうまく機能しているのに、OAuth2に「承認コード」フローがあるのはなぜですか?


264

「暗黙的」フローでは、リソース所有者(つまり、ユーザー)がアクセス権を付与した後、クライアント(ブラウザーなど)がアクセストークンを取得します。

ただし、「認証コード」フローでは、クライアント(通常はWebサーバー)は、リソース所有者(つまりユーザー)がアクセスを許可した後にのみ認証コードを取得します。次に、その認証コードを使用して、クライアントはAPIをもう一度呼び出し、client_idとclient_secretを認証コードとともに渡して、アクセストークンを取得します。ここですべてがよく説明されています

両方のフローの結果はまったく同じです。アクセストークンです。ただし、「暗黙的」フローははるかに単純です。

質問:「暗黙的な」フローがうまく機能しているのに、なぜ「認証コード」フローに煩わされるのですか?ウェブサーバーに「暗黙的」も使用しないのはなぜですか?

プロバイダーとクライアントの両方にとってより多くの作業です。



1
ありがとう、すでに読んでください。しかし、質問には答えません。
Aron

1
実際にそしてめったに答えられない良い質問:)以下を見てください。
Nicolas Garnier

1
@AronWoostサーバーWebアプリとブラウザーアプリを誤解していると思います
onmyway133

@entropyそれが私の質問でした。サーバーにブラウザフローも使用しないのはなぜですか。
Aron Woost 2014

回答:


293

tl; dr:これはすべてセキュリティ上の理由によるものです。

OAuth 2.0は、次の2つの基準を満たすことを望んでいました。

  1. 開発者が非HTTPSリダイレクトURIを使用できるようにしたいのは、すべての開発者がSSL対応サーバーを持っているわけではなく、そうでない場合は常に適切に構成されていないためです(非自己署名、信頼できるSSL証明書、同期サーバークロックなど)。
  2. ハッカーがリクエストを傍受してアクセス/リフレッシュトークンを盗むことを望まない。

以下の詳細:

暗黙的なフローは、セキュリティ上の理由により、ブラウザ環境でのみ可能です。

暗黙フローアクセストークンは(ないURLパラメータとして)ハッシュフラグメントとして直接渡されます。ハッシュフラグメントの重要な点の1つは、ハッシュフラグメントを含むリンクをたどると、ハッシュフラグメントを認識できるのはブラウザだけであることです。ブラウザーはハッシュフラグメントを宛先Webページ(リダイレクトURI /クライアントのWebページ)に直接渡します。ハッシュフラグメントには次のプロパティがあります。

  • これらはHTTPリクエストの一部ではないため、サーバーで読み取ることはできません。そのため、中間サーバー/ルーターによってインターセプトすることはできません(これは重要です)。
  • これらはブラウザー(クライアント側)にのみ存在するため、ハッシュフラグメントを読み取る唯一の方法は、ページ上で実行されるJavaScriptを使用することです。

これにより、中間サーバーによって傍受されるリスクなしに、クライアントに直接アクセストークンを渡すことが可能になります。これにはクライアント側でのみ可能であるという警告があり、アクセストークンを使用するにはクライアント側でJavaScriptを実行する必要があります。

暗黙的なフローにはセキュリティの問題もあります。たとえば、次のような回避策や回避策を講じるロジックを追加する必要があります。

  • 攻撃者は、別のWebサイト/アプリのユーザーからアクセストークンを取得し(彼が他のWebサイト/アプリの所有者である場合など)、そのトークンをWebサイトに記録し、それをWebサイトのURLパラメーターとして渡す可能性がありますしたがって、あなたのウェブサイトでユーザーを偽装します。これを回避するには、アクセストークンに関連付けられたクライアントIDを確認し(たとえば、Googleの場合、tokeninfoエンドポイントを使用できます)、トークンが独自のクライアントID(つまり、独自のアプリ)で発行されたことを確認するか、署名を確認します。 IDTokenを使用している場合(ただし、クライアントシークレットが必要です)。
  • 認証リクエストが自分のプロパティからのものではない場合(セッション修正攻撃と呼ばれます)、これを回避するには、Webサイトからランダムハッシュを生成し、それをCookieに保存して、同じハッシュを状態URLパラメータに渡します。 authリクエスト。ユーザーが戻ってきたときに、cookieで状態パラメーターを確認します。これは一致する必要があります。

認証コード流れ、URLパラメータがHTTPリクエストの一部であるため、したがって、あなたの要求が通ることになることによって、任意の仲介サーバー/ルーターが(数百かもしれない)ことになる可能性がURLパラメータに直接アクセストークンを渡すことはできません暗号化された接続(HTTPS)を使用していない場合は、アクセストークンを読み取り、中間者攻撃と呼ばれる攻撃を許可します。

アクセストークンをURLパラメータで直接渡すことは理論的には可能ですが、認証サーバーはリダイレクトURIがTLS暗号化を使用したHTTPSと「信頼された」SSL証明書を使用していることを確認する必要があります(通常、無料ではない認証局から)宛先サーバーが正当であり、HTTP要求が完全に暗号化されていることを確認します。すべての開発者がSSL証明書を購入し、ドメインでSSLを適切に構成することは非常に困難であり、採用が大幅に遅くなります。これが、正当な受信者のみが交換できる(クライアントシークレットが必要なため)中間の​​1回限りの「認証コード」が提供され、暗号化されていないトランザクションで要求を傍受する潜在的なハッカーにとってコードが役に立たない理由です。 (彼らはしないので

また、暗黙的なフローは安全性が低いと主張することもできます。たとえば、クライアントのWebサイトのIPアドレスを乗っ取るなど、リダイレクト時にドメインを偽装するなどの潜在的な攻撃方法があります。これは、暗黙的なフローがアクセストークンのみを許可する理由の1つであり(限られた時間の使用が想定されている)、トークンは更新されません(時間の制限はありません)。この問題を解決するには、可能な限りHTTPS対応のサーバーでWebページをホストすることをお勧めします。


12
@AndyDufresneこれら2つの要求はHTTPS のみをサポートする必要があるOAuthサーバーの要求であるため、HTTPSを介して実行する必要があります(必須)。HTTPSをサポートする必要のないのはクライアント/リクエスターサーバーだけなので、Auth CodeHTTP経由で送信されるのはだけです。しかし、これAuth CodeはクライアントID /シークレットなしでは役に立ちません。基本的に、OAuthコードフローの要点は、SSL対応サーバーを使用する負担は、APIのユーザー(あなた、私)ではなく、OAuthプロバイダー(Google / Facebookなど)にあるということです。
Nicolas Garnier、

5
わかりました、私は今、認証コードがプレーンHTTPを介して渡される可能性があり、盗聴されるリスクがあることを理解しました。認証コードを1回限りのコードにして、クライアントシークレットを受け入れてアクセストークンと交換すると、認証サーバーは中間者攻撃を防ぐことができます。しかし、これはアクセストークンにも適用されませんか?APIのユーザーはプレーンHTTPを使用している可能性があるため、ハッカーがアクセストークンを傍受するリスクはありませんか?PS-私は、このスレッドがアクティブになってからしばらく経った後でも、コンセプトを説明する努力に感謝します。よろしくお願いします!
アンディDufresne

8
no pb :) APIへのリクエスト(アクセストークンが(リクエストを承認するために)有線で送信されるとき)も、HTTPSを介して強制的に行われます。理論的には、クライアントは決してアクセストークンをプレーンHTTPで有線で送信するべきではありません。
Nicolas Garnier、

5
この手順のアクセストークンは、クライアントからリソースサーバーへのHTTPS要求の応答の一部です。この応答はまだ暗号化されています。
Nicolas Garnier、

13
基本的に、クライアントからリソースサーバーへのリクエストはHTTPSを介して行われます(リソースオーナーサーバーはサポートHTTPSをサポートする必要があるため)。(クライアントサーバーがHTTPSをサポートしていない可能性があるため)HTTPを介して実行される可能性があるのは、他の場所からクライアントに対して開始された要求のみです。たとえば、ユーザーがガントページで承認を付与した後の認証フロー中に発生するリダイレクトは、ブラウザーからクライアントサーバーへのリダイレクトであり、HTTPで行われる場合があります。
Nicolas Garnier

8

暗黙の流れはとても簡単、全体の流れを作るだけでなく、安全性の低いです
ブラウザー内で実行されるJavaScriptであるクライアントアプリケーションは信頼性が低いため、長期間アクセスするための更新トークンは返されません。
このフローは、ユーザーのデータへの一時的なアクセス(数時間)が必要なアプリケーションに使用する必要があります。
アクセストークンをJavaScriptクライアントに返すことは、ブラウザーベースのアプリケーションが特別な注意を払う必要があることも意味します。アクセストークンを他のシステムにリークする可能性のあるXSS攻撃について考えてください。

https://labs.hybris.com/2012/06/05/oauth2-the-implicit-flow-aka-as-the-client-side-flow


XSSの脆弱性がある場合、認証コードのフローでさえあまり役に立たないと思います。しかし、暗黙的なフローでアクセストークンをJavaScriptに渡す方法が標準化されているため(ハッシュフラグメントとして)、WebサイトにXSSの脆弱性がある場合は、URLハッシュからアクセストークンを読み取る攻撃を作成することに同意しますフラグメントは非常に簡単です。一方、認証コードフローでは、クロスサイトリクエストフォージェリが可能になる可能性があります。
Marcel

また、それはクロスサイトスクリプティングだけではありません。Webサイトで実行されているJavaScriptライブラリがアクセストークンを盗もうとする可能性があります(たとえば、JavaScriptフレームワークが使用するサードパーティのCDNライブラリやオープンソースライブラリ)。
マルセル

2
コンテンツセキュリティポリシーヘッダーとサブリソース整合性(SRI)ハッシュがあれば、XSSは大きな問題にはなりません。
Sergey Ponomarev

4

OAuth仕様から:

4.2。暗黙の付与

暗黙的な付与タイプは、アクセストークンの取得に使用され(リフレッシュトークンの発行をサポートしません)、特定のリダイレクトURIを操作することがわかっているパブリッククライアント用に最適化されています。これらのクライアントは通常、JavaScriptなどのスクリプト言語を使用してブラウザーに実装されます。

これはリダイレクトベースのフローであるため、クライアントは、リソース所有者のユーザーエージェント(通常はWebブラウザー)と対話でき、承認サーバーから(リダイレクト経由で)着信要求を受信できる必要があります。

クライアントが承認とアクセストークンに対して別々の要求を行う承認コード付与タイプとは異なり、クライアントは承認要求の結果としてアクセストークンを受け取ります。

暗黙的な付与タイプにはクライアント認証は含まれず、リソース所有者の存在とリダイレクトURIの登録に依存します。アクセストークンはリダイレクトURIにエンコードされているため、同じデバイス上にあるリソース所有者や他のアプリケーションに公開される可能性があります。

だから私たちが考慮できること:

  1. これは、公開OAuth用です。つまり、クライアントを登録する必要がなく、独自のクライアントシークレットがない場合です。しかし、どの認証サーバーがリダイレクトURLをチェックするか、これは実際にはセキュリティには十分です。

  2. アクセストークンはブラウザのアドレスバーで発生するため、ユーザーはURLをコピーして他のユーザーに送信でき、ユーザーとしてログに記録されます。つまり、セッション固定のようなものです。しかし、ブラウザは履歴を置換して追加のリダイレクトを行い、URLからハッシュフラグメントを削除します。ハッカーがHTTPトラフィックを盗聴してアクセストークンを盗むことも可能ですが、これはHTTPSによって簡単に保護できます。悪意のあるブラウザ拡張の中には、アドレスバーからURLにアクセスできるものもありますが、これは、HTTPS証明書の破損など、最終的には悪い状況です。そして、Authコードフローでさえ、ここでは役に立ちません。だから私が見ることができるのは、URLのハッシュフラグメントを介してアクセストークンを渡すことは絶対に安全であるということです。

  3. エフェメラルアクセストークンとリフレッシュトークンの分離は、HTTPSを使用する場合には無意味であり、正直なところ、生のHTTPでもそれほど役に立ちません。しかし、暗黙のフローを介したクライアントが更新トークンを受信できないという事実も意味がありません。

したがって、httpsで厳密に機能し、リフレッシュトークンを許可し(またはそれらを完全に排除する必要があり)、Auth Cose許可フローよりも好ましい新しい許可フロー「安全な暗黙的」を導入する必要があると思います


3

私たちにとって、私たちのクライアントは一度に自分の携帯電話で私たちのアプリで認証できるようになり、一度に数週間は再度ログインする必要がないことを望んでいました。コードフローでは、アクセストークンと共に更新トークンを取得します。暗黙的なフローでは、更新トークンは提供されません。アクセストークンの有効期限は比較的短いですが、更新トークンの有効期限は最大90日です。アクセストークンの有効期限が切れると、クライアントとサーバーのコードはそのリフレッシュトークンを使用して、ユーザーの介入なしに、すべての舞台裏で新しいアクセストークンとリフレッシュトークンを取得できます。更新トークンは1回しか使用できません。Implicit Flowではこれを行うことはできません。Implicit Flowを使用していて、ユーザーが1時間以上アプリを操作しない場合、ユーザーは戻ってきたときに再度ログインする必要があります。これは私たちのユースケースでは受け入れられませんでした。

リフレッシュトークンを取り消すことができるため、これは機能し、安全です。スマートフォンやラップトップを紛失した、またはハッカーがデスクトップに乗ったとお客様が言った場合、そのユーザーのすべての更新トークンを取り消すことができます。プロセス全体を通じて、個人識別情報(PII)がコード、つまりユーザーのパスワードに触れることはありません。

コードフローは素晴らしいですが、より多くの作業が必要です。MSには現在それを処理するためのAngularライブラリーがないので、私はそれを作成する必要がありました。興味があれば、お手伝いします。


2

私の答えは、Webアプリサーバーを使用して安全かつ単純な方法で暗黙的なフローを実装することはできません。

Webアプリの承認プロセスにはユーザーの操作が含まれるため、認証サーバーは、ユーザーの認証と同意の後にユーザーのブラウザーをWebアプリのターゲットページにリダイレクトして戻す必要があります(ユーザーとのやり取りの後にユーザーをWebアプリに戻す他の方法はありません。認証サーバー)。

トークンはリダイレクトURLを使用してWebアプリに渡す必要がありますよね?

@NicolasGarnierが彼の回答とコメントで説明したように、トークンをURLフラグメントとして渡す方法はありません-Webアプリサーバーに到達しません。

リダイレクトURLのURLパラメータとしてトークンを渡すことは、HTTPSでも安全ではありません。ターゲットページ(「挨拶ページ」にする)にリソース(画像、スクリプトなど)が含まれている場合、このリソースはブラウザによってシリーズを通じて取得されますHTTP(S)リクエスト(各RefererHTTPヘッダーにはURLパラメータを含む「挨拶ページ」の正確なURLが含まれています)これは、トークンが漏洩する可能性がある方法です。

したがって、リダイレクトURLでトークンを渡す方法はないようです。そのため、2番目の呼び出し(認証サーバーからクライアントへ(ただし、どのURLへ)か、またはクライアントから認証サーバーへの呼び出し(承認コードフローの2番目の呼び出し))が必要です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.