web-dev-qa-db-ja.com

すべてのリクエストでJWTを検証する必要がありますか?

上記の質問に対する明確な答えを見つけることができませんでした。

現在、認証には AWS Cognito のJWTを使用しています。現在、返されるJWTは大きすぎてCookieで使用できない(4KBの制限を超える)ため、JWT全体をCookieに格納することはしません。

現在のプロセスは、ユーザーにログインし、受信したIDトークン(JWT)を検証することです。次に、この情報からFormsAuthenticationTicketおよびCookieを作成します。 Cookieには、ユーザーの関連ID情報と、最初に受信したIDトークンのExpirationDateが含まれています。

つまり、今後のすべてのページの読み込みで、Cookieの有効期限が切れていないかどうかを確認するだけです。正しい場合は、再度ログインする必要があることがわかります。

上記は正しく機能しますか、またはJWTをCookieとして送信し、すべてのページリクエストで検証する必要がありますか?

3
StuartM

質問に直接回答するには:新しい接続を受信するたびに、セッショントークンの信頼性を確認する必要があります。これは、リクエストを受け取るたびに必ずというわけではありません。システムが複数のユーザーの要求を1つの接続に結合することがない場合(クライアントからサーバーでは非常にまれですが、たとえば、ロードバランサーからサーバーでは比較的一般的です)、接続のトークンのみを確認できます。セッションの存続期間中に一度だけ複数のリクエストを許可します(ただし、誰かがクライアントにトークンを知らずに不正なリクエストを送信させる可能性があるため、すべてのリクエストを確認するよりも危険です)。リスクが許容できる場合でも、接続が切断される前にセッションが終了(ユーザーがログアウト、タイムアウトなど)する場合は、接続の信頼を停止する必要があります。


私のコメントで示唆したように、実際にあなたのようなシステムでは、本当にCookieに何を格納しているかに依存します。たとえば、有効期限データを暗号化された整合性なしでCookie値に格納している場合、またはさらに悪いことに、ブラウザCookieの有効期限機能だけに依存している場合、is n'tがあるため、危険です誰かがその有効期限を変更するのを防ぎます。 Cookieの期限切れは、セキュリティ面でほとんど何も意味せず、ブラウザがその時点でCookieを削除するだけです。ただし、そのCookieの名前と値を知っている人なら誰でもそれを使用できます。 (おそらく、Cookieの有効期限が切れてから数か月後にログアウトしました。その名前と値でCookieを設定できます。)サーバー側で有効なCookieを追跡するか、有効期限を含める必要があります- Cookie内で、デジタル署名やメッセージ認証コード(MAC)など、何らかの形式の暗号化整合性チェックによって変更されないようにします。

ちなみに、これはJWTのしくみです。 JWTには3つの部分があります。それらの2つはデータです:ヘッダー(JWTを発行したユーザーとその有効期間など)とクレーム(発行者によると、JWTの所有者はだれであり、JWTはどのような特権を持っているかなど)です。 3番目の部分はsignatureです(これは通常HMACです。これらは通常、公開鍵署名よりも短く、検証が安価ですが、場合によっては、このような署名はより安全です)。他の部分の暗号化ハッシュ。データパーツが秘密に保たれている暗号化キーなしで偽造または変更されるのを防ぎます。 JWTを「検証」すると、暗号化操作を実行して、JWTの署名が他の部分に対して正しいこと、つまり改ざんされていないことを確認します。

あなたは「Cookieは通常JWTそのもの」と言っていますが、それは事実ですが、この場合「通常」は明らかに適用されません。 JWTの一部のみ(たとえば、署名を除くすべて)を保存する場合、それは完全に安全ではありません。別のユーザーのJWTを偽造してサーバーに送信するだけで、サーバーは、ユーザーを認証して、この切り捨てられたJWTをCookieとして渡されたと見なします。 CookieのJWTヘッダーを削除するなどの場合も同様です。署名部分は無効になっているので、正当なCookieと私が作成した(または編集して他のユーザーであると主張する)Cookieとの違いを見分けることはできません。


提案しているのは、CognitoのJWTを使用してユーザーを認証/承認し、その後の使用のために独自のセッショントークンを作成することです。これは基本的に、いくつのシングルサインオン(SSO)システムが機能するかです。一般的に、この考えには何の問題もありません。ただし、安全なセッショントークンインフラストラクチャが必要です。

大まかに言って、セッショントークンを安全に実行するには2つの方法があります。

  1. すべての認証済みユーザーに短めのトークン(通常は暗号的にランダムな文字列のみ)を発行し、サーバー側の有効なトークン(およびユーザーがマップするユーザー)のテーブルも保存します。
    • 利点:サーバーは常に、有効なトークンを認識しています。これは、ユーザーが見ることのできない有効期限情報を保存でき(編集ははるかに少ない)、トークンが早期に有効期限切れになる可能性があります(ユーザーがログアウトするか、他のセッションの終了を要求した場合)。
    • 利点:攻撃者が有効なトークンを偽造できるように盗むことができる長期的な秘密はありません。
    • 利点:唯一の暗号化操作は、トークンを作成する乱数ジェネレーターです。
    • 短所:サーバーのクラスターを実行する場合、サーバーはすべて、トークンが有効かどうかを常に確認できる必要があります。これには、分散メモリキャッシュ、ロードバランシングをバイパスしてユーザーを1つのサーバーにロックするトリッキーな動作、またはデータベースクエリ全体が必要です。
    • 評決:単純ですが、適切にスケーリングされません。
  2. セッションの詳細(ユーザーID、承認、セッションの有効期限など)を含むトークンを作成し、秘密の暗号化キーを使用してトークンに署名し、ユーザーがトークンを変更または偽造できないようにします。これがJWTの仕組みです。
    • 利点:サーバー側の状態がまったくありません。すべてのサーバーがトークンの検証に必要なキーを知っている限り、サーバーはどのセッションがアクティブであるかについて何も覚えておく必要はありません。
    • 利点:トークンは1つのサーバーによって発行され、別のサーバーによって使用されます。検証サーバーが発行サーバーを信頼している限り、同じエンティティが所有している必要はありません。非対称(公開鍵)暗号化により、発行サーバーは有効なトークンを作成するために必要な「秘密鍵」を秘密に保つことができ、対応する「公開鍵」を持つサーバーはそれらを検証できます。
    • 欠点:トークンを早期に期限切れにするのは困難です。それを行う方法はいくつかありますが、それらは面倒で、適切にスケーリングされません。したがって、トークンは通常、有効期間が短く、定期的に再発行されます(多くの場合、最初のタイプの「リフレッシュトークン」を介して発行されます。これは、スケーラビリティの問題にならないためにめったに使用されません)。
    • 欠点:署名キーはシステム全体の要です。攻撃者がそれを取得した場合、攻撃者は有効なトークンを偽造でき、サーバーはその違いを知ることができません。署名キーの定期的なローテーションは役立ちますが、非常に短い妥協(署名キーが攻撃者に知られてから、信頼された署名キーでなくなるまでの期間)でも壊滅的なものになる可能性があります。
    • 欠点:暗号化を正しく行うのは困難です。これは非常に単純な暗号システムですが、それでも十分な可動部分があり、だれかがそれをだましてしまうリスクがあります。また、たとえば、署名の作成に使用された暗号化ハッシュが破損し、誰かが同じハッシュを生成する別のトークン本文を作成できる場合にもリスクがあります。ここでの回避策は、何をしているのかを知っている人々によって書かれレビューされた信頼できる実装を使用し、それを最新の状態に保ち、最新の暗号プリミティブ(たとえば、SHA2またはSHA3ファミリ)を使用することです。 SHAまたはMD5)。
    • 評決:すべての種類と規模のシステムで使用できますが、正しく理解するのが難しく、致命的に失敗する可能性が高くなります。

長所と短所のリストを見ると、最初のアプローチの方が良いと思うかもしれませんが、スケーリングの問題は多くのシステムにとって大きな問題であることがわかります。ハイブリッドアプローチ(短命なタイプ2アクセストークンとセッションライフタイムタイプ1リフレッシュトークンを使用して新しいアクセストークンを取得できる)はうまく機能しますが、多少複雑になりますが、それでも削除されません署名鍵を完全に秘密にしておく必要があり、アクセストークンを安全に検証する必要があります。

2
CBHacking