TL; DR:認証にoauth2を使用することのセキュリティ上の意味は何ですか?
ユーザーがよりシンプルなインターフェイスを介して別のWebサイト(サイトB)で操作を実行できるようにするアプリ(サイトA)を構築しています。
サイトBは、アプリの承認のためにOAuth2.0を実装するAPIを提供します。
サイトBの認証に便乗することで、パスワードを保存したり、ユーザーにアプリで別のアカウントを取得させたりすることを回避できると考えていました。
もちろん readliteraturebashing on the ---(use of plain OAuth for authentication ですが、私はこれがセキュリティの観点からどのように悪いのかを見落としています。
彼らは主にソリューションの実用性と(欠如)ソリューションに焦点を当てているようです。
これが私が考えていたスキームです:
ここでは、いわゆる「サーバー側フロー」を使用していることに注意します。また、3番目のステップで返されるauthorization_code
は、Aのclient_idに関連付けられた、短期間の1回限りのコードであり、対応するclient_secret
でのみ使用できます。
サリーが別のデバイスからログインすると、プロセスが繰り返され、新しいトークンが保存されます。
私が目にする唯一の問題は、ユーザーが初回だけでなくログインごとに私のアプリを承認するように求められることですが、現時点ではそれは問題ではありません。また、実際に有効なトークンがある場合は、新しいトークンを要求します。少し実用的ではありませんが、現時点では問題ありません(*)。
私が見落としているのは、これがセキュリティの観点からいかに悪いかということです。
そのようなスキームの場合:ユーザーのセキュリティ問題は何ですか?そしてアプリのために?
何かが足りないような気がします。
(*)私には大きなユーザーベースはなく、ホワイトリストに登録された数人のユーザーしかありません。アプリが大きくなった場合は、実際のOpenID Connectプロバイダーを使用する大きなサイトにアプリを統合する予定です。このパイロットテスト中は、シンプルで小さく、焦点を絞っていたい
注:OAuth2のようなものを探しているが、認証には、
代わりに OpenId Connect を使用してください。
OAuth2は、ユーザーがアプリケーションを承認して、リソースプロバイダーからユーザーのリソースを読み込むことを目的としています。言い換えると、OAuth2は、承認の委任のためのメカニズムです。このプロトコルは認証をサポートしていません(ただし、一般的にそれが正しく使用されているためです)。
セキュリティホールは、5番目の箇条書きで行う前提にあります。
あなたは言う:
サイト[〜#〜] a [〜#〜]はサイト[〜#〜] b [〜#〜]にサリーは
user_id
であり、そのIDでログインします
実際にはそれは読むべきです:
サイト[〜#〜] a [〜#〜]はサイト[〜#〜] b [〜#〜]に
user_id
がアクセスを許可するユーザーデータからのaccess_token
.
すべてが予定どおりに進んだ場合、access_token
は確かに、リダイレクトするユーザーから[〜#〜] b [〜#〜]に認証されます。しかし、そうであるという保証はありません。実際、ユーザーが以前にユーザーのデータにアクセスする権限を付与した(悪意のある)Webサイト([〜#〜] b [〜#〜]でOAuth2を使用)、 [〜#〜] b [〜#〜]から有効なauthorization_code
を取得し、箇条書き3で送信できます。
つまり、OAuth2を使用して[〜#〜] b [〜#〜]でリソースへのアクセス許可をユーザーに求めるWebサイトを実行すると、すべての権限を借用できます認証にOAuth2([〜#〜] b [〜#〜]をOAuth2承認サーバーとして使用)を悪用するすべてのWebサイトのユーザー。
OAuth2の「問題」は、特定のauthorization_code
に対してclient_id
が生成されないことです。したがって、authorization_code
を受け取った場合、[〜#〜] b [〜#〜]がauthorization_code
を発行したかどうかはわかりませんあなた、または他のサービスに。これはauthorizationでは許容可能と見なされますが、authenticationではまったく許容できません。
更新:
コメントについて:
(そして私は以前にBにリダイレクトしたユーザーから1つだけを受け入れるようにAを制限していますが、これはまだ認証されていません)
OAuthプロトコルでは必須ではありません。そのため、これに依存することはできません。
Jaccoによって説明されているように、oauth2に基づく認証の単純な実装にはいくつかの脆弱性があり、最も一般的なものは [〜#〜] csrf [〜#〜] です。
完全に優れた認証プロトコル があり、これらすべての落とし穴がなくても利用できることを考えると、自分でロールすることはお勧めできません。
OTOH、それを実行し、これらの問題を理解して修正することによって学ぶべきことがたくさんあります。
TL; DR:なぜそれをすべきでないかを学ぶためにそれをしているのでない限り、認証にoauth2を使用しないでください。 OpenID Connectを使用します。
何よりもまず、oauth2の脅威モデルの広範な分析が RFC6819 にあります。
Oauth2にはいくつかの可能な「フロー」があります。私のプロジェクトで焦点を当てたのは、authorization_code
フローでした。
RFC6819がそれについて言っていることは次のとおりです。
承認「コード」は、成功したエンドユーザー承認プロセスの中間結果を表し、アクセストークンと更新トークンを取得するためにクライアントによって使用されます。承認「コード」は、次の2つの目的で、トークンの代わりにクライアントのリダイレクトURIに送信されます。
ブラウザベースのフローは、URIクエリパラメータ(HTTPリファラー)、ブラウザキャッシュ、またはログファイルエントリを介してプロトコルパラメータを潜在的な攻撃者に公開し、再生される可能性があります。この脅威を減らすために、トークンの代わりに有効期間の短い認証「コード」が渡され、クライアントと認証サーバー間のより安全な直接接続を介してトークンと交換されます。
クライアントと許可サーバー間の直接要求時にクライアントを認証する方が、間接許可要求の場合よりもはるかに簡単です。後者にはデジタル署名が必要です。
だから認証コードはもっと安全です、そうです!
authorization_code
フローの脆弱性は、RFC6819の セクション4.4.1 で分析されています。
このセクションは多くの根拠をカバーしています。いくつかの脅威に焦点を当てます。
セクション4.4.1.8から:
攻撃者は、承認サーバー上の保護された独自のリソースに対して承認「コード」を承認する可能性があります。次に、デバイス上のクライアントへのリダイレクトフローを中止し、被害者をだましてクライアントへのリダイレクトを実行させます。クライアントはリダイレクトを受信し、認証サーバーからトークンをフェッチして、被害者のクライアントセッションを、トークンを使用してアクセス可能なリソースに関連付けます。
影響:ユーザーは攻撃者に代わってリソースにアクセスします。 [...]たとえば、ユーザーがプライベートアイテムを攻撃者のリソースにアップロードする可能性があります
これは RFC6749のセクション10.12 でもカバーされています。
クライアントは、リダイレクトURIにCSRF保護を実装する必要があります。これは通常、リダイレクトURIエンドポイントに送信されるすべてのリクエストに、リクエストをユーザーエージェントの認証済み状態にバインドする値(ユーザーエージェントの認証に使用されるセッションCookieのハッシュなど)を含めることを要求することで実現されます。クライアントは、承認リクエストを行うときに「state」リクエストパラメータを使用して、この値を承認サーバーに配信する必要があります(SHOULD)。
したがって、oauth2プロバイダーへのリダイレクトでは、パラメーターstate
を追加するだけです。これは、単なるCSRFトークンです(推測できないようにする必要があり、安全なCookieに保存するなど)。このトークンは、oauth2プロバイダーがユーザーをリダイレクトすると、authorization_code
とともに返されます。
この攻撃への対策は、クライアントと認証サーバーの両方で実装する必要があり、認証サーバーで実施することもできます。
状態パラメータは このセクションのSEの質問 でも説明されています。
これは(RFC6819のセクション4.4.1.13で説明されています)、特にoauth2シナリオでの認証を目的としています。
基本的に、攻撃者は悪意のあるサイト(サイトCと呼ぶことにします)を通じてユーザーのauthorization_code
を取得し、それを正当なサイト(サイトAと呼びます)に送信します。リソースサーバーを通じてユーザーのIDをアサートするために使用されます。これにより、攻撃者はサイトAのユーザーとしてログインできます。
これは、ジャッコが彼の答えで述べたものです。
この攻撃への対策は、承認サーバーで実装する必要があります。
すべてのクライアントは、認証「コード」をアクセストークンと交換するすべてのリクエストでクライアントIDを示す必要があります。許可サーバーは、特定の許可「コード」が特定のクライアントに発行されたかどうかを検証する必要があります。可能であれば、クライアントは事前に認証されます。
信じられないかもしれませんが、以前の攻撃とその対策は、コードフローを使用した場合の認証に対する脅威のほとんどをカバーしています。
他にも多くの脅威と対策があり、その多くは常に実装する必要があります。
セクション4.4.1.3から:
ハンドルベースのトークンは、高エントロピーを使用する必要がありますクライアントを認証します。これは、攻撃者が認証 "コード"をリダイレクトURIにバインドすることを推測する必要がある別の値を追加します。これにより、攻撃者が推測する必要がある別の値が追加されます。トークンの有効期限を短くする
これらはすべて承認サーバーで実装する必要があります。
セクション4.1.1.4から:
承認サーバーはクライアントを認証する必要があります承認サーバーは、事前登録されたリダイレクトURIに対してクライアントのリダイレクトURIを検証する必要があります
これらは、承認サーバーでも実装する必要があります。
セクション4.4.1.5、4.4.1.6などから:
クライアントのリダイレクトURIはHTTPSで保護されたエンドポイントを指す必要があります
これはクライアントによって実装されるべきであり、おそらく認証サーバーによって実施されるべきです。
いいえ。しないでください。 OpenID Connectを使用します。
セクション4.4.1.13の対策を覚えていますか?さて、私が引用しなかった別のものがありました:
クライアントは、OpenID([OPENID]を参照)またはSAML([OASIS.sstc-saml-bindings-1.1]を参照)などの適切なプロトコルを使用して、ユーザーログインを実装する必要があります。どちらもクライアントの視聴者制限をサポートしています。
どうぞ。代わりにそれを使用してください。
それでもoauth2プロバイダーに対して認証する必要がある場合は、まず、プロバイダーが前述のすべての対策を実装していることを確認してください。
もしそうなら、それを引き出すことができるかもしれません。広範なテストを行い、セキュリティチームを雇って、ソリューションの完全な分析を実行します。
また、セキュリティに依存するすべてのプロバイダーの機能がプロバイダーのAPIに文書化されていることを確認してください。そうしないと、それらは事前の通知なしに削除され、最終的にVery Broken™製品になる可能性があります。
私の場合:-運が良かったので、プロバイダーがこれらの対策をすべて実装しました。 -アプリの初期テスト期間を超えて、認証にこれに依存していません(これは私のアプリの必須機能ではなく、単にリリース前の便利なプレースホルダーです)
また、この実装全体でoauth2について十分に学び、価値のあるものにしました。
詳細を知りたい場合は、RFC6819とRFC6749の両方を読んでください。 このサイト も非常に役に立ちました。
フローのセキュリティホール:
彼女はサイトBの認証ページにリダイレクトされ、そこで認証されますまたはアクティブなセッションがあります
ユーザーがサイトBでアクティブなセッションを持っている場合、他のWebサイト(サイトC、Dなど)はOAuthシステムBのシステムを認証に使用できます。悪意のあるサイト(例:サイトx)は、サイトBからアクセストークンを取得し、トークンの再生を使用してサイトのユーザーになりすまし、ユーザーが許可していないアクションを実行する可能性があります。リンクのFacebookの例をもう一度読んで、問題を説明してください。
スキーム全体の課題は、サイトがOAuthサイトBのAPIと同じくらい安全になることです。先ほど示したように、サードパーティが悪用する可能性があるため、APIは安全ではありません。悪用の場合、唯一の手段はサイトBにサイトxの禁止を求めることです。個人的に私は自分のセキュリティの運命を私が所有していないサイトの手に任せたくありません。
より安全なメカニズムでは、サイトBの承認済みのクライアントのリストOAuthクライアントに対して、できれば公開キークライアント証明書を使用して、サイトの認証を提供し、トークンの使用を要求元サイトに制限することによってトークンの再生を防ぎます。サイトBにそのようなアクセススキームを強制することはできないため、サイトBが提供するセキュリティのレベルに制限されます。