tl;dr:
client_id
ネイティブ クライアントはおよびで認証できませんclient_secret
。クライアントを認証する必要がある場合は、共有シークレットをクライアントに委ねない (またはクライアント認証の議論にエンドユーザーを巻き込む) 認証スキームを実装する必要があります。アプリケーションのセキュリティ モデルによっては、クライアントを認証する必要がない場合があります。
- 通常、リダイレクト エンドポイントは、クライアントを認証するのに十分ではありません (例外はありますが)。
- 「クライアントクレデンシャル」グラントタイプは、クライアント登録時に与えられるクレデンシャルを含め、認可サーバーがサポートする任意のクライアント認証メカニズムを使用できます。
私が読んだ要点は、機密クライアントのclient_id
(読み取り: "ユーザー名") とclient_secret
(読み取り: "パスワード") を信頼して、サービスでそれらを認証できるということです。第三者のアプリケーションがそのクライアントの資格情報で自分自身を表す可能性はありません[1]。
ただし、パブリック クライアントはそのような保証を行うことはできません。ブラウザ ベースのアプリケーションであろうと、ネイティブ デスクトップ アプリケーションであろうと、クライアントの ID とシークレットは世界中に配布されます。このようなアプリケーションは、クライアントを掘り下げて ID とシークレットを抽出できる熟練した開発者やハッカーの手に渡ると考えるのが妥当です。このため、セクション 10.1 では次のように明示的に述べています。
The authorization server MUST NOT issue client passwords or other
client credentials to native application or user-agent-based
application clients for the purpose of client authentication.
わかった。そのため、パブリック クライアントはパスワードで認証できません。しかし…</p>
The authorization server MAY issue a client password or other
credentials for a specific installation of a native application
client on a specific device.
この例外は、クライアントの認証を特定のデバイスに関連付けるために機能します。つまり、誰かがクライアントの秘密を持ち去ったとしても、それを再利用することはできません。ただし、この例外で暗黙的に示されているのは、「特定のデバイスへの特定のインストール」は、一意に識別可能で、なりすましが難しく、そのクライアントの認証プロセスに不可欠である必要があるということです。
すべてのネイティブ アプリケーションがこれらの基準を満たすことができるわけではありません。また、ブラウザー ベースのアプリケーションが実行される環境では、一意に識別できるものやなりすましが難しいものは何もないため、確実に満たすことはできません。これにより、いくつかの選択肢が生まれます。クライアントを認証されていないものとして扱うか、より適切な認証メカニズムを考え出すことができます。
認証ダンスの鍵は共有シークレットです。これは、承認サーバーと認証クライアントだけが知っているものです。 パブリック クライアントの場合、クライアント自体に秘密はありません。 ありがたいことに、選択肢はあります。RFID キー フォブやバイオメトリクスについてだけ話しているわけではありません (ただし、それらは完全に受け入れられます)。
思考実験として、ブラウザベースのクライアントを考えてみましょう。それについていくつかのことを合理的に推測できます: それはブラウザーで実行され、特定のドメインから提供され、そのドメインはクライアントの作成者によって制御されます。認証サーバーにはクライアント リダイレクト URI が既にあるはずなので、そこには何かがありますが、仕様では次のように説明されています。
A valid redirection URI is not sufficient to verify the client's
identity when asking for resource owner authorization but can be
used to prevent delivering credentials to a counterfeit client
after obtaining resource owner authorization.
そのため、リダイレクト URI は確認する必要がありますが、信頼できるものではありません。主な理由は、ドメインがなりすましの可能性があるためです。しかし、サーバー自体はそうすることができないので、クライアントのドメインのサーバーだけが知っていることをドメインに尋ねてみることができます。これを行う最も簡単な方法は、クライアントのシークレットがホストされるクライアントと同じドメインで、認証サーバーが 2 番目の (「プライベート」) URI を要求することです。クライアント アプリケーションが認可リクエストを行うと、サーバーは、クライアントから報告されたホスト名に関連する2 番目の URI に対して「チェックイン」し、共有シークレットを探します (認可サーバーにのみ開示する必要があります)。
もちろん、これは完璧な解決策ではありません。すべてのアプリケーションで機能するわけではなく、間違いやすく、実装に多大な労力がかかる可能性があります。多くの潜在的な認証メカニズム (非常に特殊なものと非常に一般的なものの両方) が存在し、クライアント アプリケーションにプライベート データを委ねないものは、この問題領域に適しています。
もう 1 つのオプションは、それ以上の認証を実装せず、クライアントを認証されていないものとして扱うことです。これは特に、未登録のクライアントと同じではありませんが、違いはわずかです。未登録のクライアントは、ID が不明なクライアントです。認証されていないクライアントとは、ID はわかっているが信頼されていないクライアントです。両方のタイプのクライアントに対するセキュリティの意味は同じです。どちらにも個人データを委ねるべきではありません。ただし、認可サーバーがこれら 2 つのケースを同じように扱うことを選択するかどうかは、実装者に任されているようです。たとえば、API がすべてを拒否することは理にかなっています。未登録のクライアントからの接続、および公開された読み取り専用コンテンツを登録済みのクライアントに提供する (クライアントの身元を確認しなくても)。
ただし、プラグマティズムはまだ勝つ可能性があります。認証されていないクライアントは、ブラウザがサイトの SSL 証明書の信頼性を確認できない場合に時折見られる SSL「エラー」と基本的に違いはありません。ブラウザはすぐにそれ以上の処理を拒否し、正確な理由を報告しますが、ユーザーはサーバーの身元を保証することでリスクを受け入れることができます. 同様のワークフローは、多くの OAuth2 アプリケーションにとって理にかなっています。
とにかく、クライアントの身元を確認することが重要なのはなぜですか? そうしないと、信頼の連鎖が壊れてしまいます。アプリケーションのユーザーはアプリケーションを信頼します。認可ワークフローは、ユーザーがクライアントも信頼することを確立するため、アプリケーションはクライアントを信頼する必要があります。クライアント ID を検証しないと、別のクライアントがやって来て、信頼されたクライアントの役割を引き受け、そのすべてのセキュリティ権限を持つ可能性があります。クライアント認証に関するすべては、信頼の侵害を防ぐために役立ちます。
これが役に立ったことを願っています!
[1]: アプリケーションのソース コードが悪意のあるユーザーの手に渡るサーバー侵害は例外であり、その場合のために他の保護手段が組み込まれています。そうは言っても、仕様では、単純なユーザー名とパスワードの組み合わせが最も安全なオプションではないことも具体的に指摘しています。
The authorization server is encouraged to consider stronger
authentication means than a client password.