ステートレスREST APIを実装しています。フレームワークまたは0Authに組み込まれたセッションを使用するのに慣れていますが、現在、フレームワークとサービスに依存する代わりに、独自のjwtベアラー認証実装を開発中です。私が作成中の設計上の決定について質問があるので、認証の専門家の何人かが私を助けてくれることを願っています。
私は主にNodeJS、Express、MongoDBを使用して集中型認証サーバーを作成しました。この認証サーバーは、この認証サーバーを共有する2つの個別のアプリケーション(将来はもっと多く)からのアクセスを許可するつもりです。登録、ログイン、ルート保護を適切に行い、完全に機能していますが、すべてが正しく接着されていることを確認したいと思います。
秘密鍵を変更したり(EveryoneのPWをリセット)したり、DBをヒットしてユーザーのDBフラグをチェックしたりせずに、ユーザーアクセスを個別に無効にするために次のことができるかどうか疑問に思っています:
ユーザーはパスワードusernameでログインします->認証サーバーはクライアントに10分のライフタイムを持つJWTを返し、認証された後続の各リクエストとともにリソースサーバーに渡されます。次に、リソースサーバーは有効性をチェックし、クレームを解析して新しいリクエストを提供します。 auth api応答authヘッダーの更新されたトークン。
詐欺などの理由でユーザーが非アクティブに設定されたとしましょう-有効なJWT署名/ exp/claimに従ってセッションがまだアクティブであるにもかかわらず、このアカウントへのアクセスを削除する必要があります。制限が設けられていない限り、許可された使用。私のポイントは、トークンをDBに保存することを避けながら、検証された各リクエストでユーザーのコレクションをアクティブ状態にチェックすることなく、トークンに基づいてユーザーリクエストを即座に無効化できることです。
私は、リフレッシュトークンを模倣することですが、JWTでrefreshTokenクレームとして送信する代わりに、有効なリクエスト(たとえば、auth.user.status === 'active'
に対してチェックされる)が行われた場合、すべての応答で送信するベアラートークンを上書きします。 5分のトークンタイムアウトとユーザー入力により、セッション拡張が要求されます。このトークンは、その寿命を自動的に延長するだけで、ユーザーがログアウトする必要はありません。これは、使用しているWebクライアントが構成された期間アクティブのままである限り、ログアウトが自動的に行われるためです。このアプローチでは、DB内のトークンのブラックリストも必要ありません。トークンを更新する前に、タイムアウトが近づいていることをユーザーに警告するUIコンポーネントを実装する予定です。このアプローチに問題はありますか? authヘッダーを新しいベアラートークンの形式でそれ自体の延長されたライフタイムバージョンに置き換えることができる場合の更新トークンのポイントは何ですか(各要求の後にグローバルに保存され、各要求と共に送信されるなど)。私とこの面で混乱している他の人のためにこれを解決するのを助けてくれてありがとう。
Pro:認証のためにデータベースを厳密にチェックする必要はありません。
Con:トークンがデータベース/ストアで無効になったときから有効期限が切れるまでの残り時間-ユーザーはアクティブのままで、トークンが期限切れになるまでアクセスできます。削除、非アクティブなどに設定.
ログアウトまたは無効化されたすべてのユーザー認証トークンをdBに保存し、アクセスを許可する前にブラックリストを確認します。
トークンが検証されたサブクレームによってuser.statusがあるかどうかDBを確認します。私
プロ:
提供されるアクセストークンの信頼性に関係なく、必要に応じてユーザーを即座に無効にする機能。
短所:
APIベアラーインターセプターミドルウェアにデータベースユーザールックアップを追加したり、無効化されたトークンをルックアップに挿入してトークンブラックリストの管理をさらに悪化させることにより、パフォーマンスが大幅に低下しました。
トークン検証中のauth.user.stateはAPIに状態を導入しませんか?
更新トークンが通常のアクセストークンと異なるのはなぜですか?更新トークンは通常、アクセストークンの場合よりもはるかに長い寿命を持っていますが、それはなぜですか?ここで何が欠けていますか?
リクエストごとに有効な認証済みトークンのライフタイムを延長し、認証APIからクライアントに送信された既存のベアラートークンを新しい短いライフスパンJWTで上書きし、クライアントに戻し、リソースに再び使用されるようにします。サーバ?このようにすると、有効期限内にアカウントをシャットダウンできるので、認証リクエストごとにデータベースのユーザーステータスを確認するしかありません。両方のアプリケーションが同じ方法でuser.statusを使用するため、私はそれを大きな問題とは見なしていませんが、コードのこの部分は書かれていないので、何人かから聞きたかったのです!
ユーザーがn時間またはn分以内に認証されたリクエストを行わない場合は、トークンを期限切れにします。それ以外の場合は更新を続けるか、トークンが期限切れになる前にまだ認証されているユーザーが更新を希望するかどうかを確認します。
安全のために、すべてのクレームとステータス(トークンではない)をDBのuser.authコレクションと照合し、トークンの署名を検証しています。
したがって、あなたの目標は、データベースを必要とせずに、ユーザーのトークンをすぐに無効にできるようにすることです。 コメントで言う のように、これは実際には不可能です。
私はあなたのデザインがこれを成し遂げるとは思わない。
あなたの設計についての私の理解は、ユーザーが無効になったときにdbに記録する代わりに、それらに無効のマークを付けるトークンを送り返すことで、後続の呼び出し(トークンを更新できないことを含む)を防ぐことです。
私が正しく理解している場合、ユーザーに無効なトークンを発行すると、ユーザーはそのトークンの更新を無視して以前のトークンを続行することを選択できます。これにより、更新され、無効なユーザーがセッションを無期限に延長できるようになります。
これは、クライアントソフトウェアが正しく動作しており、前のCookieを削除して削除することを前提としています。
私はあなたが成功事例についてのみ考えており、クライアント自体が悪意のあるものである可能性があることを考慮していないと思います(意図的にユーザーの側で、またはマルウェアが原因です)。たとえば、クライアントがすべてのトークンを記録している場合、またはクライアントがすべてのHTTP要求と応答を記録するBurpなどのHTTPプロキシを経由している場合はどうなりますか?
私は引用を発明することで終了します:
クライアントが正直であることに依存するセキュリティは、犬にクッキーを守るように頼むのと同じくらい便利です。 -私
サーバーがセキュリティを実施する唯一の方法は、サーバーがセキュリティを実施することです。つまり、サーバーは何が起こっているのかを知る必要があります。そうでない場合、悪意のあるクライアントがセキュリティを回避するためにできることは何もないことを証明できる必要があります。あなたがコメントで言うように、これを行う唯一の本当の方法はDBを使用することです。