検証器モジュールを実装する前にこのセクション全体を読んで理解してください。 機能不全の検証器は、それが提供する誤った安全感と、OAuthエコシステムの他の部分に対する攻撃に寄与する可能性があるため、全くセキュリティがないよりも潜在的に悪いです。
異なるモジュールは、トークンバリデーションに対して非常に異なるアプローチをとることがありますが、実装は一般に、3つの別個のアクションを実行する必要があります。
検証器は、まず、提示されたトークンが実際にクライアント認証で使用するための有効なベアラトークンであることを確認する必要があります。 これを行う正しい方法はプロバイダに依存しますが、通常は、トークンが信頼できる組織によって作成されたことを証明するための暗号処理(オフラインバリデーション)、またはバリデーションを実行できるようにその信頼できる組織にトークンを提示する(オンラインバリデーション)ことが含まれます。
オンライン検証(通常はOAuthトークンイントロスペクションを介して実装される)では、検証器モジュールの手順が少なくて済み、盗難または誤発行されたイベントのトークンを一元的に失効させることができます。 ただし、モジュールは、認証の試行ごとに少なくとも1つのネットワーク呼び出しを行う必要があります(これらはすべて、設定されたauthentication_timeout内で完了する必要があります)。 また、プロバイダは、外部リソースサーバが使用するイントロスペクションエンドポイントを提供しない場合があります。
オフライン検証ははるかに複雑であり、通常検証器はプロバイダのトラステッド署名キーのリストを維持し、チェックはトークンの暗号署名とその内容を維持する必要があります。 実装は、発行者(「このトークンはどこから来たのか?」)、オーディエンス(「このトークンは誰のためのものか?」)、有効性ピリオド(「このトークンはいつ使用できるのか?」)の検証を含む、プロバイダの指示に従わなければなりません。 モジュールとプロバイダの間には通信がないため、このメソッドを使用してトークンを一元的に取り消すことはできません。 オフライン検証器の実装では、トークンの有効性ピリオドの最大長さに制限を設けることができます。
トークンが検証できない場合、モジュールは直ちに失敗します。 ベアラトークンが信頼できる組織によって発行されていない場合、それ以上の認証/認可は無意味です。
次に検証器は、エンドユーザが、彼らに代わってサーバによるクライアントアクセスの許可を与えていることを確認しなければなりません。 これには通常、現在のHBAパラメータによるデータベースアクセスをカバーしていることを確認するために、トークンにアサインされたスコープをチェックすることが含まれます。
このステップの目的は、OAuthクライアントが虚偽の理由でトークンを取得するのを防ぐことです。 検証器がすべてのトークンにデータベースアクセスを可能にする内容を伴うことを要求する場合、処理中にプロバイダはユーザにアクセス許可を明示的に求める必要があります。 これにより、クライアントが資格情報を使用してデータベースに接続することになっていない場合に、リクエストを拒否する機会が与えられます。
デプロイされたアーキテクチャに関する外部から得た知識を用いることで、明示的なスコープを用いずにクライアント認可を確立することも可能ですが、そうするとユーザを処理の中から排除し、設定の誤りに気が付かなくなることになり、その誤りが気が付かないうちに悪用されることになります。 もしユーザが追加のスコープの入力を求められない場合は、データベースへのアクセスは信頼できるユーザ [17] にのみしっかりと制限されなければなりません。
認可が失敗した場合でも、モジュールは、監査およびデバッグで使用するために、トークンから認証情報を引き続き取得し続けることを選択できます。
最後に、検証器は、プロバイダにこの情報を要求するか、トークン自身からこの情報を抽出することによって、識別子をサーバに返します(サーバはHBA設定を使用して最終的な認可を決定します)。
log_connectionsが有効になっている場合、この識別子はsystem_userを介してセッション内で使用可能になり、サーバログに記録されます。
様々なプロバイダが、あるエンドユーザの様々な認証情報を記録する場合があります、通常は要求(claims)と呼ばれます。 プロバイダは通常、これらの要求のうち、許可決定に使用できるほど信頼できるものと信頼できないものを記録します。 (たとえば、多くのプロバイダでは、ユーザがディスプレイ名を任意に変更できるので、エンドユーザのフルネームを認証の識別子として使用することは賢明ではありません。) 結局のところ、どの要求(または要求の組合せ)を使用するかの選択は、プロバイダの実装とアプリケーションの要件に依存します。
ユーザマップ委任を有効にすることで、匿名/仮名のログインも可能であることに注意してください。50.1.3を参照してください。
開発者は、トークンバリデーションを実装する際に、次の点に留意する必要があります。
モジュールは、サーバログにトークンまたはトークンの断片を書き込むべきではありません。 モジュールがトークンを無効だと見なしたとしても、これは当てはまります。クライアントを混乱させて間違ったプロバイダと通信させようとする攻撃者が、ディスクから(そうでなければ有効な)トークンを取得できるべきではありません。
(例えば、プロバイダとオンライントークンバリデーションを行うために)ネットワークを介してトークンを送信する実装は、ピアを認証し、強力なトランスポートセキュリティが使用されていることを確認する必要があります。
モジュールは、標準の拡張機能と同様に、同じロギングファシリティを使用できます。ただし、コネクションの認証フェーズ中にクライアントへログエントリを出力する際のルールは、微妙に異なります。
一般的に、認証されていないクライアントへの情報の漏洩を回避するために、ERROR/FATALを使用してスタックを巻き戻すのではなく、検証上の問題をCOMMERRORレベルでログに記録し、正常に終了する方が適切です。
モジュールは、サーバが正しく認証タイムアウトとpg_ctlからのシャットダウンシグナルを処理できるように、シグナルによる割り込みが可能でなければなりません。
たとえば、ソケット上のブロッキング呼び出しは、一般的にソケットイベントと割り込みの両方を競合せずに処理するコードに置き換えるべきで(WaitLatchOrSocket()、WaitEventSetWait()、などを参照してください)、長時間実行されるループはCHECK_FOR_INTERRUPTS()定期的に呼び出しする必要があります。
このガイダンスに従わないと、バックエンドセッションが応答しなくなる可能性があります。
OAuthシステムのテストの幅は、この文書のスコープをはるかに超えていますが、少なくともネガティブテストは必須であると考えるべきです。 許可されたユーザをログインさせるモジュールを設計するのは簡単です。 システムの全体的なポイントは、許可されていないユーザを締め出すことです。
DBAがpg_identマップを作成するためにこの情報を使用する必要があるかもしれないので、実装はサーバに報告される各ユーザの認証されたIDの内容と形式を文書化する必要があります。
(たとえば、それはメールアドレスか?組織ID番号か?UUIDか?)
また、モジュールをdelegate_ident_mapping=1モードで使用するのが安全かどうか、そしてそうするための追加の設定は何かも文書化するのが良いでしょう。
検証モジュールの標準的な成果物はユーザ識別子であり、サーバは設定されたpg_ident.confマッピングと比較して、エンドユーザが接続を認可されているかどうかを判断します。
ただし、OAuthは自分自身で認可フレームワークであり、トークンはユーザ特権に関する情報を運ぶ場合があります。
たとえば、トークンはユーザが属する組織グループに関連付けられたり、ユーザが引き受ける役割をリストに関連付けられたりすることがあり、その情報をすべてのサーバのローカルユーザマップに複製することは望ましくない場合があります。
ユーザ名マッピングをバイパスし、検証器モジュールにユーザ接続を許可する追加の責任を負わせるには、HBAをdelegate_ident_mappingで構成します。 モジュールは、トークンスコープまたは同等のメソッドを使用して、ユーザが目的のロールの下で接続できるかどうかを決定します。 ユーザ識別子はサーバによって記録されますが、コネクションを継続するかどうかを決定する際には関係ありません。
この方式を使用すると、認証自体はオプショナルになります。 モジュールがコネクションが許可されていることを報告する限り、ユーザ識別子がまったく記録されていなくてもログインは続行されます。 これにより、データベースに匿名または仮名のアクセスを実装することが可能になります。 この場合、サードパーティプロバイダは必要な認証をすべて実行しますが、ユーザを識別する情報をサーバに提供しません。 (プロバイダによっては、後で監査するために、代わりに記録できる匿名化されたID番号を作成する場合があります。)
ユーザマップ委任は、最も柔軟なアーキテクチャを提供しますが、検証器モジュールをコネクション認可の単一障害点にしてしまいます。 注意して使用してください。
[17] つまり、OAuthクライアントとPostgreSQLサーバが同じエンティティによって制御されているという意味での「信頼できる」です。 特に、libpqによってサポートされているデバイス認証クライアントフローは、パブリック/信頼できないクライアントによって使用されるように設計されているため、通常はこの基準を満たしません。