web-dev-qa-db-ja.com

ユーザーのアクセス許可をJWTクレームに格納したり、リクエストごとにサーバーで確認したりする方が効率的ですか?

[〜#〜] jwt [〜#〜] は、ユーザーに送信されるデータとユーザーに返送されるデータが改ざんされていないことを確認する優れた方法ですが、いくつかの難しい選択になります。現時点では、JWTクレームに認証データを保存するか、認証のためにデータベースに1回のみタッチするか、データベースを使用してサーバーへの各リクエストのユーザーIDを保存して認証レベルを確認するかを選択するジレンマに陥っています。

これを困難な選択にしているのは、アプリケーションが複数の認証レベルで動作するため、base64でエンコードされたURLが非常に長くてかさばるということです(認証レベルとして格納できるものを以下に示します)。

一方、認証を取得するには、データベースで2つのルックアップが必要です。

だから私の質問は次のとおりです。 サーバーにアクセス許可を送信することにより、各要求の余分なオーバーヘッドは、各要求のアクセス許可を探す手間を避ける価値がありますか?

補足として;権限が変更された場合、データベースのルックアップ方式には、ユーザーが再度ログインする必要がないという利点があります( 投稿を参照 )。

"perms": {
    "roles": [
        {
            "name": "Admin",
            "id": 1,
            "assigned": true
        },
        {
            "name": "Webmaster",
            "id": 8,
            "assigned": true
        }
    ],
    "actions": [
        {
            "id": 1,
            "name": "cms-edit",
            "parameters": null,
            "parameterized": null
        },
        {
            "id": 9,
            "name": "admin-syslog",
            "parameters": null,
            "parameterized": null
        },
        {
            "id": 10,
            "name": "admin-debug",
            "parameters": null,
            "parameterized": null
        },
        {
            "id": 12,
            "name": "member-list-extended",
            "parameters": null,
            "parameterized": null
        },
        {
            "id": 2,
            "name": "cms-list",
            "parameters": null,
            "parameterized": null
        },
        {
            "id": 3,
            "name": "cms-add",
            "parameters": null,
            "parameterized": null
        },
        {
            "id": 5,
            "name": "member-list",
            "parameters": null,
            "parameterized": null
        },
        {
            "id": 7,
            "name": "member-view",
            "parameters": null,
            "parameterized": null
        },
        {
            "id": 8,
            "name": "member-edit",
            "parameters": null,
            "parameterized": null
        }
    ]
11
Tom Stock

最初の質問:

サーバーにアクセス許可を送信することにより、各要求のオーバーヘッドが増えるので、各要求でアクセス許可を調べる煩わしさを回避できますか?

回答:

JWTをいつ使用するかについてjwt.ioが提供する説明を見てみましょう。

承認:これは、JWTを使用するための最も一般的なシナリオです。ユーザーがログインすると、後続の各リクエストにはJWTが含まれ、ユーザーはそのトークンで許可されているルート、サービス、リソースにアクセスできます。シングルサインオンは、オーバーヘッドが小さく、さまざまなドメイン間で簡単に使用できるため、現在JWTを広く使用している機能です。

つまり、ユーザーがログインしたら、サーバー側でトークンを生成する必要があります。

を含む:

  • ユーザー(IDまたは名前として)
  • クライアントの役割(ユーザー、管理者、ゲスト、その他...)

クライアントがサーバーにデータを要求または送信すると、サーバーは最初に、指定されたトークンが有効で既知であるかどうかをチェックし、次に、ロールが特定のリソースにアクセスするための基準を満たしているかどうかをチェックします。

すべての役割/アクセスデータは、システムの起動時に一度読み取り、メモリに保持できます。さらに、クライアントが持つロールは、クライアントのログイン時にデータベースから1回だけ読み取られます。これにより、後続のデータベースアクセスがなくなり、パフォーマンスが大幅に向上します。

一方、クライアントがデータを要求する場合、またはアクションを実行する場合は、渡されたトークンがそのために必要なロールを取得しているかどうかを評価する認証メカニズムが必要です。

これにより、データベースの煩わしさを解消し、クライアントに過剰な情報を公開する危険性を排除しました(クライアントがデータを改ざんできなくても、データを読み取ることができます!)

そのことに注意してください: https://jwt.io/introduction

署名付きトークンを使用すると、トークンに含まれるすべての情報は、変更できない場合でも、ユーザーまたは他の関係者に公開されることに注意してください。つまり、秘密の情報をトークンに含めないでください。

A3(機密データの露出)を参照してください: https://www.owasp.org/index.php/Top_10-2017_Top_1

最後に、クライアントのアイドル時間が長すぎる場合、または意図的にログアウトした場合も、トークンを無効にします。

フォローアップ質問:

権限の変更により、データベースのルックアップのアプローチが変わるため、ユーザーが再度ログインする必要がないという利点があります。

回答:

サーバーのインフラストラクチャに応じて、更新メカニズムを作成することもできます(ロールが更新されると、サーバーは新しいトークンを生成し、生成された回答と一緒にクライアントに送信し、古いトークンを無効にします。クライアントは最新のトークンのみを使用し、 old)またはサーバー側でクライアントセッションのようないくつかの状態を追加します。

トークンの役割/権限を排除します。クライアントのセッションを生成し、サーバー側でセッションの役割/権限をフィードする方がよいでしょう。クライアントは、認証に使用できるセッショントークン(通常はID)を取得します。権限/役割を変更したら、2つのことを行う必要があります。

  1. データベースを更新する
  2. セッションの役割/権限を更新する

繰り返しになりますが、後続のすべてのリクエストはロール/権限チェックをメモリ内で実行し、データベース通信は必要ありませんが、クライアントには小さなセッショントークン(またはJWT)しかありません。したがって、役割/権限の変更はクライアントに対して透過的であり(再ログは必要ありません)、JWT更新要件を排除しました。

12
Akar

効率の解釈方法によって異なります。リソース効率について話すとき、JWTはすべてのリクエストで送信されることに注意してください。したがって、きめの細かいアクセス制御リスト(ACL)を備えた大規模なアプリケーションがあり、これらのリストをすべての要求/応答で常にピンポンする場合、発行する要求の数に応じて数キロバイトのコストがかかることになります。

2
B12Toaster