個人/趣味のアプリケーション用にKoaベースのNode.jsバックエンドがあります。
JWTトークンを使用してセッション処理を実装しました。クライアント(AngularJS)は、ログインが成功した後にトークンを取得し、トークンをどこかに保存します(現在はsessionStorage
にありますが、この質問の目的では問題ではありません)。
2つの質問があります:
JWTが表すユーザーレコードを更新する必要がある場合、たとえば、ユーザーが2要素認証(2FA)をオンにしたので、彼に電話番号を提供するように依頼し、この電話番号をユーザーレコードに設定したいと思います。現在、電話番号の確認に成功した後、バックエンドに電話してユーザーレコードを更新し、更新されたユーザーレコードを使用して新しいJWTトークンを作成します(ハッシュされたパスワードなどの機密情報をJWTトークンから除外しますが、クライアント側で使用するための電話番号を含める)。一部の資格情報が変更されたときに新しいトークンを作成し、この新しいトークンで既存のクライアント側トークンを更新しても大丈夫ですか?認証が成功した場合にのみ、トークンを作成するためだけに、別のトークンを作成することは絶対にしないでください。次に、トークンのペイロードを更新するにはどうすればよいですか?
期限切れのJWTトークンをどのように処理する必要がありますか?私の頭の中には3つの(可能な)シナリオがあります:
2.1。 JWTは短命、たとえば15分に設定されています。バックエンドサーバーが401 Unauthenticated 'Invalid token'(これはkoa-jwt
のデフォルトの動作だと思います)で応答した場合、自動的にログに記録されます-クライアントを出力し、再認証が必要です。ただし、補完的なミドルウェアもセットアップしました。これは、バックエンドのチェーンの最後で、有効期限が更新されたトークンを再作成します。クライアントは、既存のトークンを更新されたトークンに置き換えます。したがって、ユーザーがアクティブで、保護されたAPI呼び出しごとにアプリケーションを使用する場合、成功した場合は、古いトークンを置き換える新しいトークンが作成されます。
2.2。 JWTは、たとえば1週間の長寿命に設定されており、有効期限が切れた場合は、クライアントからの再認証をオプトインします。
2.3。コピー https://tools.ietf.org/html/rfc6749#section-1.5 。ここでは、認証が成功した後にJWTトークンを作成するときに、access_tokenとrefresh_tokenを送信します。 access_tokenの有効期限が切れ、サーバーがHTTP 401 'invalid token'(koa-jwt
default)で応答すると、クライアントはrefresh_tokenを新しいaccess_token(およびオプションで新しいrefresh_token)を必要とするバックエンド。この場合、新しいトークンを提供するために、refresh_tokenが古いaccess_tokenに対してどのように検証されるかを完全に理解していませんか?または、なぜrefresh_tokenが必要なのですか?
上位のトピック(JWTの更新とJWTの有効期限)に関する一般的なアドバイスが役立ちます。
下から始めて、更新トークンはここでは役に立たないと思うので無視します。これらは通常、クライアントアプリケーションがユーザーブラウザよりも安全なストレージを提供できる他のシナリオを対象としています。ネイティブモバイルアプリケーションやサーバー側のWebアプリケーションを考えてみてください。
更新トークンは存続します。つまり、クライアントがサーバーからトークンを取得する場合、潜在的な攻撃者がトークンを使用しないように、このトークンを安全に保存する必要があります。このため、ブラウザに保存するのは安全ではありません。
(強調は私のものです;ソース トークンの更新 )
これは、オプション2.3が基本的に2.2と同じであることを意味しますが、これは悪いオプションではありません。セッション期間が長いWebアプリケーションがあることは珍しいことではありません。アプリケーションの感度が高くない場合は、長いセッションを使用してユーザーエクスペリエンスを向上させることができます。たとえば、Djangoは、セッションCookieの経過時間としてデフォルトの2週間を使用します。 SESSION_COOKIE_AGE を参照してください。
残りのオプション(2.1)は、通常、スライディングセッションと呼ばれます。セッションのタイムアウトは短いですが、ユーザーがその間隔内にアプリケーションを使用し続ける限り、セッションは自動的に更新されます。これはおそらく最も一般的なアプローチであるか、少なくとも私が最も頻繁に使用したアプローチであるため、偏見があります。私が注意する唯一のことは、スライディングセッションは通常、クライアント側にCookieとして保存された不透明なセッション識別子を使用して実装され、次にサーバーに保存された実際のセッションデータを使用して実装されることです。
ブラウザのローカルストレージにステートレスJWTトークン(実際のユーザーデータが含まれている)が保存されているため、アプローチは少し異なります。あなたが言ったように、トークンを更新するには、新しい署名を生成する必要があるため、新しいトークンを生成する必要があります。
署名は、JWTの送信者が本人であることを確認し、メッセージが途中で変更されていないことを確認するために使用されます。
(強調は私のものです;ソース JSON Webトークン )
そうは言っても、私は次のことを検討します。
そうは言っても、JWTはそれほど大きくないことも考慮する必要がありますが、自動的に更新することにした場合は、それでもオーバーヘッドになります。 20分のセッション期間を選択し、セッションの半分が経過した後にのみ自動更新を実行することで、これを少し軽減できます。
もう1つのポイントは、挿入されたスクリプトがlocalStorage
/sessionStorage
から読み取ることができるため、アプリケーションのXSSのような脆弱性により、アクセストークンが攻撃者に公開されることです。これは別の利点となる可能性があります。 HTTPのみのセッションCookieストレージ。
最初の質問に進む前に、2番目の質問に答えたいと思います。
基本的に、あなたが言及した3番目のオプションは、アクセストークンを更新するための最良の方法です。アクセストークンの寿命は短く(約5分)、更新トークンの寿命は長くなります。アクセストークンの有効期限が切れたら、更新トークンをバックエンドに送信して、新しいアクセストークンを取得します。したがって、応答は次のようになります。
_{
"token_type":"bearer",
"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiVlx1MDAxNcKbwoNUwoonbFPCu8KhwrYiLCJpYXQiOjE0NDQyNjI4NjYsImV4cCI6MTQ0NDI2Mjg4Nn0.Dww7TC-d0teDAgsmKHw7bhF2THNichsE6rVJq9xu_2s",
"expires_in":10,
"refresh_token":"7fd15938c823cf58e78019bea2af142f9449696b"
}
_
したがって、アイデアは、アプリケーションを承認サーバー(アクセストークン/更新トークンを生成する)とリソースサーバー(アクセストークンを検証してリソースにアクセスする)に分離することです。スキーマを維持して、AuthorizationServerのアクセストークンに対して更新トークンを検証できます。このリンクに記載されているスキーマのセクションを参照してください。 Oauth2 。必要に応じてスキーマを変更できます。リクエスト呼び出しごとに、アクセストークンと一緒に更新トークンを送信する必要はありません。更新トークンは、新しいアクセストークンを生成するために承認サーバーにのみ送信できます。更新トークンを生成する方法は? Javaを使用している場合は、UUID.randomUUID()
を使用して一意の更新トークンを生成します。
最初の質問に答えるために、更新されたユーザーレコードに基づいてJWTペイロードを更新する場合は、同じ更新トークンを使用して、更新されたペイロードで新しいアクセストークンを生成できます。電話番号がユーザーレコードに存在する場合はペイロードに追加され、存在しない場合はペイロードでnullになるため、ロジックは同じままです。
更新トークンを使用する主な利点は、アクセストークンを更新トークンを使用していつでも更新できることです。