web-dev-qa-db-ja.com

JWT検証クライアント側?

angularフロントエンドを備えたnodejs apiがあります。APIは、JWTとパスポートを使用して、エンドポイントを保護します。

トークンの有効期限が切れた後も、フロントエンドにより、ユーザーはログインの詳細を再入力して新しいトークンを取得するように求めることなく、APIエンドポイントをリクエストできます。

これが私のバックエンドがトークンを生成する方法です:

_function generateToken(user) {
  return jwt.sign(user, secret, {
    expiresIn: 10080 // in seconds
  });
}
_

したがって、このロジックを実装するには、JWTトークンのクライアント側を検証する必要があると思います。 Q1、これは賢明なアプローチです。

Q2、私が使用している JWT ライブラリは、verify()関数を使用するために公開鍵を必要とするようです。私は公開鍵を持っているようには見えませんが、作成したばかりの秘密だけなので、ペアで生成されませんでした。公開鍵はどこから来たのですか、またはこれなしでトークンを確認する別の方法はありますか?

これはすべて明白であるように見え、私が何かを見逃しているようです。これが愚かな質問である場合は謝罪しますが、答えを見つけることができないようですか?

13
George Edwards

TL; DR

  1. verifyserver alwaysのJWSの署名を指定する必要があります。
  2. クライアント側の署名の検証は、意味のある特定のケースがない限り、あまり役に立ちませんしないでください
  3. クライアントで有効期限を確認するためにJWSトークンの署名を確認する必要はありません。 (クレームを暗号化していない限り、別名JWEを使用します。その場合、クレームを復号化するためのキーが必要なため、同様のことを行う必要があります)。
  4. サーバーで有効期限を確認するためにJWSの署名を検証する必要もありませんが、これにより、誰も有効期限を変更していないことが確実になるため、検証する必要があります。異なります)
  5. 暗号化されていないクレームを読み取るには、デコードするだけです。クライアントでは jwt-decode を使用できます。

トークンの有効期限が切れた後も、フロントエンドでユーザーがAPIエンドポイントをリクエストできるようになることを私は今意識しています[...]

このロジックを実装するには、クライアント側のJWTトークンを確認する必要があると思います

私があなたを正しく理解していれば、JWSがクライアント側で期限切れになったかどうかを確認することについて話しています。これを行うために、トークンの署名を確認する必要はありません(使用しているライブラリは 同時に両方 を実行しているようですが、有効期限の制御を無効にすることもできます) ignoreExpirationフラグ付き)。 (クレームを暗号化している場合を除き、別名JWEを使用) RFC 7515(JWS) は、有効期限については何も述べていません。 メッセージの署名またはMAC検証 は有効期限を制御しません(署名は信頼性と整合性を提供するため、制御する必要はありません)。 RFC 7519(JWT) でも、JWT が有効かどうか の場合、解決のための有効期限クレームを制御しません。

また、すべての クレームはオプション です。

したがって、署名を検証せずにJWTの有効期限が切れているかどうかを確認できます。したがって、公開鍵(RSAのような非対称暗号化の場合)や秘密鍵(AESのような対称暗号化の場合)は必要ありません。 JWTトークンとJWSトークンでは、クレームはプレーンテキストのbase64でエンコードされているため、 署名が有効かどうかを確認せずにペイロードをデコード して、有効期限クレームを読み取ることができます。ペイロードを暗号化している場合(別名JWEを使用)、これを行うことはできません。

jjwt library からのメモ

JWTは暗号化することができますsigned(それを[〜#〜] jws [〜#〜]にする)またはencrypted(それを-にする) [〜#〜] jwe [〜#〜])。

ここJWT/JWSトークンのbase64encodedクレームをデコードするauth0のligthweigthライブラリです。男は 有効期限の確認 についてさえ尋ねています。

クライアント側でこの制御を行うべきだと思う理由がわかりません。唯一の利点は、クライアントが失敗することを知っているAPI要求を送信しないことです。そして、サーバーはトークンの有効期限が切れていないことを検証する必要があるため、失敗するはずです。以前の署名検証(秘密/秘密鍵による)は明らかに。

RFC 7519 はこの主張について述べています。

「exp」(有効期限)クレームは、JWT 処理のために受け入れられてはならない以降の有効期限を識別します。

トークンの使用のようなWebアプリでは、ステートレスサーバーがクライアント要求を認証できるようにすることです。 [〜#〜] optional [〜#〜]有効期限クレームの目的は、サーバーが生成されたJWSをある程度制御できるようにすることです(JWTを認証に使用している場合は、それらに署名する必要があります) JWSについて話している必要があります)。

有効期限がなければ、トークンは永久に、またはトークンの署名に使用されたキーが変更されるまで有効です(これにより、検証プロセスが失敗します)。ちなみに、 無効化セッション は、ステートレス認証を使用することで最も悪名高い欠点の1つです。

ユーザーがどのロールを持っているかなど、認証に使用されるJWSペイロード(別名クレーム)に情報を含める場合、セッションの無効化は実際の問題になります。

From セッションでのJWTの使用を停止

しかし、もっと深刻なことに、管理者の役割を取り消したばかりの場合でも、誰かが管理者の役割を持つトークンを持っていることを意味します。トークンも無効にできないため、管理者アクセスを削除する方法はありません

有効期限の制御はこの問題を解決しません。セッションのハイジャックやCSRF攻撃を回避する方が向いていると思います。

CSRFを使用する攻撃者は、有効期限の制御をスキップして、有効期限が切れたJWSでAPIにリクエストを行うことができます。

別の問題は、公開鍵または秘密鍵を使用してクライアントの署名を検証することです。

ご質問について

私が使用しているように見えるのは、それのverify()関数を使用するための公開鍵です。私は公開鍵を持っていないようです。秘密だけです。作成したばかりなので、ペアで生成されていません。

あなたが指摘した検証メソッドは、公開鍵または秘密鍵を受け入れることを明示的に言っています。

jwt.verify(token, secretOrPublicKey, [options, callback])

secretOrPublicKeyは、HMACアルゴリズムのシークレット、またはRSAおよびECDSAのPEMエンコードされた公開鍵のいずれかを含む文字列またはバッファです。

どちらも使用しておらず、 'shhhh'のような文字列を使用していると思います。

var token = jwt.sign({ data: '¿Donde esta Santiago?'}, 'shhhh');

その後、あなたはすべきです

var decoded = jwt.verify(token, 'shhhhh');

ただし、ここでの質問は次のとおりです。クライアント側の署名検証は本当に必要ですか?

少なくとも、クライアントがJWSを使用してサーバーに後続のリクエストを送信するだけのこの種のアプリケーションはそうではないと思います。「サーバー、私はガブリエルです。これを保証する紙(トークン)があります。その紙はあなたによって署名されています。」したがって、クライアントがJWSを検証せず、MITMがそのクライアントに(サーバーが署名したJWSではなく)自分で署名したJWSを正常に付与した場合、その後の要求は単純に失敗します。有効期限制御と同様に、署名の検証は、クライアントが失敗する要求を行うことを防ぐだけです。

現在、クライアント側の検証では、公開鍵または秘密鍵を送信する必要があります。公開鍵の送信はセキュリティ上の問題ではありませんが、余分な労力と処理であり、ほとんどメリットがありません。

秘密鍵( 'shhhh'など)の送信は、トークンの署名に使用されるのと同じ鍵であるため、セキュリティの問題を表す可能性があります。

11
gabrielgiussi

Q1:クライアントでのトークン検証は悪い考えです。あなたができることは、クライアントに同じ有効期限と一緒にトークンを保存してから、トークンを更新/削除することです。しかし、サーバー側の原因でいくつかの日付チェックを行う方がよいという私の考えは、クライアントを信頼しない常に悪意のあるコードを送信する可能性があるためです。

Q2:JWTは公開鍵を必要としません。誰かがあなたの秘密鍵、あなたのトークンを知っている場合、それは常にサーバー側に秘密鍵を保存する必要があります。ペイロードを追加するだけで、より複雑になります。

1
Dmitry

クライアント側でJWTトークンを検証することは良い考えではないと思います。
IMO;

  1. ユーザーがログインするたびに、アクセストークンと更新トークンを生成し、次のようなものをユーザーに返します。

    { "accessToken": <<accessToken>> "refreshToken": <<refreshToken>> "expiresAt": <<expiresAt>> }

    そのため、クライアントはアクセストークンの有効期限が切れたことを理解し、更新トークンで更新できます。

  2. シークレットキーなしでデータにアクセスする可能性があるため、アクセストークンに入れたデータを暗号化します。しかしもちろん、誰かが鍵を秘密にして確認する必要があります。

0
ugursogukpinar