web-dev-qa-db-ja.com

JWTトークンのサーバー側処理のベストプラクティス

このスレッド から生成されます。これは実際にはNodeJSなどに固有ではなく独自の問題であるため)

認証付きのREST AP​​Iサーバーを実装しています。ユーザーがJWTトークンを生成するために、ユーザーがユーザー名/パスワードを使用して/ loginエンドポイントからログインできるように、JWTトークン処理を正常に実装しました。サーバーシークレットとクライアントに返されます。次に、トークンは、認証された各APIリクエストでクライアントからサーバーに渡され、サーバーシークレットがトークンの検証に使用されます。

しかし、真に安全なシステムを作成するために、トークンを検証する方法と程度を正確に示すためのベストプラクティスを理解しようとしています。トークンの「検証」に関与する必要があるのは正確に何ですか?サーバーシークレットを使用して署名を検証できれば十分ですか、それともトークンやトークンペイロードをサーバーに保存されているデータと照合する必要がありますか?

トークンベースの認証システムは、ユーザーのパスワードを取得するよりもトークンを取得することが同等以上に難しい場合に限り、各リクエストでユーザー名/パスワードを渡すのと同じくらい安全です。ただし、私が見た例では、トークンを生成するために必要な情報は、ユーザー名とサーバー側の秘密だけです。これは、悪意のあるユーザーがサーバーシークレットの知識を得ると1分間仮定すると、anyユーザーに代わってトークンを生成できるようになることを意味しませんか?これにより、パスワードが取得された場合のように特定の1人のユーザーだけでなく、実際にはallユーザーアカウントにアクセスできますか?

これは私に質問をもたらします:

1)JWTトークンの検証は、トークン自体の署名の検証、サーバーシークレットの整合性のみに依存する、または別の検証メカニズムを伴うことに限定する必要がありますか?

  • 場合によっては、/ loginエンドポイントからのログインに成功するとセッションが確立されるトークンとサーバーセッションを組み合わせて使用​​することがあります。 APIリクエストはトークンを検証し、トークンで見つかったデコードされたデータをセッションに保存されたデータと比較します。ただし、セッションを使用することはCookieを使用することを意味し、ある意味ではトークンベースのアプローチを使用する目的に反します。また、特定のクライアントに問題を引き起こす可能性があります。

  • サーバーが現在使用中のすべてのトークンをmemcacheなどで保持していると想像できます。これにより、サーバーのシークレットが侵害され、攻撃者が「有効な」トークンを生成できる場合でも、/ loginエンドポイントから生成された正確なトークンのみが生成されます受け入れられます。これは合理的ですか、それとも単なる冗長/過剰ですか?

2)JWT署名検証がトークンを検証する唯一の手段である場合、つまりサーバーシークレットの整合性がブレークポイントである場合、サーバーシークレットをどのように管理する必要がありますか?環境変数から読み取り、デプロイされたスタックごとに1回作成(ランダム化?)しますか?定期的に更新またはローテーションします(ローテーション前に作成されたが、ローテーション後に検証する必要がある既存の有効なトークンの処理方法。サーバーが特定の時点で現在および以前のシークレットを保持している場合は、おそらくそれで十分です) ?他に何か?

サーバーの秘密が危険にさらされるというリスクに関しては、私は単に過度に妄想的です。これはもちろん、すべての暗号化状況で対処する必要があるより一般的な問題です...

102
JHH

私も自分のアプリケーションのトークンで遊んでいます。私は決して専門家ではありませんが、この問題に関する私の経験や考えの一部を共有できます。

JWTのポイントは、本質的に整合性です。これは、サーバーに提供されたトークンが本物であり、サーバーによって提供されたことをサーバーが検証するメカニズムを提供します。あなたの秘密を介して生成された署名は、これを提供するものです。ですから、はい、あなたの秘密が何らかの形で漏洩した場合、その個人はあなたのサーバーがそれ自身だと思うトークンを生成できます。トークンベースのシステムは、単に署名の検証のために、ユーザー名/パスワードシステムよりも安全です。この場合、誰かがあなたの秘密を持っている場合、システムには、偽のトークンを作成する誰かよりも対処すべきセキュリティ上の問題があります(さらに、秘密を変更するだけで、古い秘密で作成されたトークンは無効になります)。

ペイロードに関しては、署名は、提供されたトークンがサーバーが送信したときとまったく同じであったことを通知するだけです。ペイロードの内容がアプリケーションにとって有効または適切であることを検証するのは、明らかにあなた次第です。

ご質問:

1.)私の限られた経験では、2番目のシステムでトークンを検証する方が間違いなく優れています。署名を検証するだけで、トークンがあなたの秘密で生成されたことを意味します。作成されたトークンを何らかのDB(redis、memcache/sql/mongo、またはその他のストレージ)に保存することは、サーバーが作成したトークンのみを受け入れることを保証する素晴らしい方法です。このシナリオでは、たとえ秘密が漏洩したとしても、生成されたトークンはいずれにしても有効ではないので、それほど重要ではありません。これは私のシステムで取っているアプローチです-生成されたすべてのトークンはDB(redis)に保存され、リクエストごとに、トークンを受け入れる前にDBにあることを確認します。このようにして、何らかの理由でトークンを取り消すことができます。たとえば、何らかの形で野生にリリースされたトークン、ユーザーのログアウト、パスワードの変更、シークレットの変更などです。

2.)これは私があまり経験がないものであり、セキュリティの専門家ではないので、私はまだ積極的に研究しているものです。リソースを見つけたら、ここに投稿してください!現在、私は単にディスクからロードする秘密鍵を使用していますが、明らかにそれは最良または最も安全なソリューションとはほど遠いです。

51
Akshay Dhalwala

アプリケーションにJWTを実装する際に考慮すべき事項を次に示します。

  • JWTの有効期間を比較的短くし、その有効期間をサーバーで管理します。不要で、後でJWTでより多くの情報を必要とする場合、2つのバージョンをサポートするか、古いJWTの有効期限が切れるまで待ってから変更を実装する必要があります。 jwtのiatフィールドだけを見て、expフィールドを無視すれば、サーバー上で簡単に管理できます。

  • JWTにリクエストのURLを含めることを検討してください。たとえば、JWTをエンドポイント/my/test/pathで使用する場合は、'url':'/my/test/path'などのフィールドをJWTに含めて、このパスでのみ使用されるようにします。そうしないと、他のエンドポイントで作成されていないものも含め、他のエンドポイントでJWTの使用を開始することがあります。また、代わりにmd5(url)を含めることを検討することもできます。JWTに大きなURLがあると、JWTがさらに大きくなり、かなり大きくなる可能性があるためです。

  • JWTがAPIに実装されている場合、JWTの有効期限は各ユースケースで構成可能でなければなりません。たとえば、JWTの10の異なるユースケースに対応する10のエンドポイントがある場合、各エンドポイントが異なる時間に期限切れになるJWTを受け入れるようにすることができることを確認してください。これにより、たとえば、あるエンドポイントが提供するデータが非常に機密性の高い場合、一部のエンドポイントを他のエンドポイントよりもロックダウンできます。

  • 一定時間後にJWTを単に期限切れにする代わりに、両方をサポートするJWTの実装を検討してください。

    • N回の使用-有効期限が切れる前にN回のみ使用でき、
    • 一定の時間が経過すると期限切れになります(1つのトークンのみを使用している場合、使用しないと永遠に存続したくないでしょうか?)
  • すべてのJWT認証の失敗は、JWT認証が失敗した理由を示す「エラー」応答ヘッダーを生成する必要があります。例えば「期限切れ」、「使用法はありません」、「失効」など。これにより、実装者はJWTが失敗する理由を知ることができます。

  • JWTが情報を漏らし、ハッカーに制御の尺度を与えるため、JWTの「ヘッダー」を無視することを検討してください。これは主にヘッダーのalgフィールドに関するものです-これを無視し、ヘッダーがサポートしたいものであると想定してください。これは、ハッカーがNoneアルゴリズムを使用して署名セキュリティチェックを削除するのを防ぐためです。

  • JWTには、どのアプリがトークンを生成したかを詳述する識別子を含める必要があります。たとえば、2つの異なるクライアントmychatとmyclassifiedsappによってJWTが作成されている場合、それぞれにプロジェクト名またはJWTの「iss」フィールドに類似したものを含める必要があります。 「iss」:「mychat」

  • JWTはログファイルに記録しないでください。 JWTの内容は記録できますが、JWT自体は記録できません。これにより、開発者や他のユーザーがログファイルからJWTを取得したり、他のユーザーアカウントに対して操作を実行したりすることができなくなります。
  • ハッカーがトークンに署名せずにトークンを作成しないように、JWT実装で「なし」アルゴリズムを許可しないようにしてください。このクラスのエラーは、JWTの「ヘッダー」を無視することで完全に回避できます。
  • JWTでiat(有効期限)の代わりにexp(発行日)の使用を強く検討してください。どうして? iatは基本的にJWTがいつ作成されたかを意味するため、作成日に基づいてJWTの有効期限が切れたときにサーバー上で調整できます。誰かが将来20年後のexpを渡すと、JWTは基本的に永遠に生き続けます! iatが将来的な場合はJWTを自動的に期限切れにしますが、クライアントの時間がサーバーの時間とわずかに同期していない場合に備えて、少しのゆらぎ(10秒など)を考慮してください。
  • JSONペイロードからJWTを作成するためのエンドポイントの実装を検討し、すべての実装クライアントがこのエンドポイントを使用してJWTを作成することを強制します。これにより、JWTを1か所で簡単に作成する方法を使用して、必要なセキュリティ問題に対処できます。 5つの異なるクライアントの実装に時間が必要なため、アプリでこれをすぐに行うことはせず、JWTサーバー側のセキュリティ更新をゆっくりと細流化する必要があります。また、作成エンドポイントが、作成するJWTのjsonペイロードの配列を受け入れるようにします。これにより、クライアントのこのエンドポイントに着信するhttp要求の数が減ります。
  • セッションによる使用もサポートするエンドポイントでJWTを使用する場合は、要求を満たすために必要なものをJWTに入れないでください。 JWTが提供されていないときにエンドポイントがセッションで動作することを確認すれば、これを簡単に行うことができます。
  • そのため、JWTの一般的に言えば、ある種のuserIdまたはgroupIdが含まれ、この情報に基づいてシステムの一部へのアクセスを許可します。特に機密データへのアクセスを提供する場合は、アプリのある領域のユーザーが他のユーザーになりすますことを許可しないようにしてください。どうして? JWT生成プロセスに「内部」サービスのみがアクセスできる場合でも、開発者または他の内部チームはJWTを生成して、あらゆるユーザーのデータにアクセスできます。ランダムなクライアントの会社のCEO。たとえば、クライアントの財務記録へのアクセスをアプリが提供する場合、JWTを生成することにより、開発者はどの会社の財務記録も取得できます。とにかくハッカーが内部ネットワークに侵入した場合でも、同じことができます。
  • JWTを含むURLを何らかの方法でキャッシュできるようにする場合は、JWTではなく、異なるユーザーのアクセス許可がURLに含まれていることを確認してください。どうして?ユーザーはデータを取得する可能性があるため、そうすべきではありません。たとえば、スーパーユーザーがアプリにログインし、次のURLを要求するとします:/mysite/userInfo?jwt=XXX、およびこのURLがキャッシュされること。彼らはログアウトし、数分後、通常のユーザーがアプリにログインします。キャッシュされたコンテンツを取得します-スーパーユーザーに関する情報が含まれています!これは、特にAkamaiのようなCDNを使用しており、一部のファイルの寿命を延ばす場合に、クライアントでは少なく、サーバーではより多く発生する傾向があります。これは、関連するユーザー情報をURLに含め、サーバー上でこれを検証することで修正できます。たとえば、/mysite/userInfo?id=52&jwt=XXX
  • JwtがセッションCookieのように使用されることを意図しており、jwtが作成されたのと同じマシンでのみ動作する場合は、jwtに jti フィールドを追加することを検討する必要があります。これは基本的にCSRFトークンであり、JWTをあるユーザーのブラウザーから別のユーザーに渡すことができないようにします。
38
Brad Parks

私は専門家だとは思いませんが、Jwtについてのいくつかの考えを共有したいと思います。

  • 1:Akshayが言ったように、トークンを検証するための2番目のシステムを用意する方が良いでしょう。

    a .:処理方法:生成されたハッシュを有効期限とともにセッションストレージに保存します。トークンを検証するには、サーバーによって発行されている必要があります。

    b .:使用する署名方法を確認する必要があるものが少なくとも1つあります。例:

    header :
    {
      "alg": "none",
      "typ": "JWT"
    }
    

JWTを検証する一部のライブラリは、ハッシュをチェックせずにこれを受け入れます。つまり、トークンに署名するために使用されるソルトを知らなくても、ハッカーは自分自身にいくつかの権利を与えることができます。これが起こらないことを常に確認してください。 https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/

c .:セッションIDでCookieを使用することは、トークンの検証には役立ちません。誰かがラムダユーザーのセッションをハイジャックしたい場合、スニファーを使用する必要があります(例:wireshark)。このハッカーは、両方の情報を同時に取得します。

  • 2:これはすべてのシークレットで同じです。常にそれを知る方法があります。

私がそれを処理する方法は、ポイント1.aにリンクされています。 :ランダム変数と混合した秘密があります。秘密はすべてのトークンに対して一意です。

しかし、真に安全なシステムを作成するために、トークンを検証する方法と程度を正確に示すためのベストプラクティスを理解しようとしています。

可能な限り最高のセキュリティが必要な場合、盲目的にベストプラクティスに従うべきではありません。最善の方法は、あなたが何をしているのかを理解し(あなたの質問を見たときに大丈夫だと思います)、必要なセキュリティを評価することです。そして、Mossadが機密データにアクセスしたい場合、彼らは常に方法を見つけます。 (このブログ投稿が好きです: https://www.schneier.com/blog/archives/2015/08/mickens_on_secu.html

ここにはたくさんの良い答えがあります。最も関連性が高いと思われる回答の一部を統合し、さらにいくつかの提案を追加します。

1)JWTトークンの検証は、トークン自体の署名の検証、サーバーシークレットの整合性のみに依存する、または別の検証メカニズムを伴うことに限定する必要がありますか?

いいえ、トークンシークレットの侵害とは無関係の理由によります。ユーザーがユーザー名とパスワードを介してログインするたびに、承認サーバーは、生成されたトークン、または生成されたトークンに関するメタデータを保存する必要があります。このメタデータは承認レコードと考えてください。指定されたユーザーとアプリケーションのペアは、常に1つの有効なトークン、つまり承認のみを持っている必要があります。有用なメタデータは、アクセストークンに関連付けられたユーザーID、アプリID、およびアクセストークンが発行された時刻です(これにより、既存のアクセストークンの取り消しと新しいアクセストークンの発行が可能になります)。すべてのAPI要求で、トークンに適切なメタデータが含まれていることを検証します。アカウントの資格情報が侵害された場合にユーザーが既存のアクセストークンを取り消し、再度ログインして新しいアクセストークンの使用を開始できるように、各アクセストークンが発行された時期に関する情報を保持する必要があります。これにより、アクセストークンが発行された時刻(作成された承認時刻)でデータベースが更新されます。すべてのAPIリクエストで、アクセストークンの発行時刻が作成された承認時刻より後であることを確認します。

その他のセキュリティ対策には、JWTをログに記録せず、SHA256などの安全な署名アルゴリズムを要求することが含まれます。

2)JWT署名検証がトークンを検証する唯一の手段である場合、つまりサーバーシークレットの整合性がブレークポイントである場合、サーバーシークレットをどのように管理する必要がありますか?

サーバーシークレットの侵害により、攻撃者は任意のユーザーにアクセストークンを発行でき、ステップ1でアクセストークンデータを保存しても、サーバーがそれらのアクセストークンを受け入れることを必ずしも妨げるわけではありません。たとえば、ユーザーにアクセストークンが発行され、その後、攻撃者がそのユーザーのアクセストークンを生成したとします。アクセストークンの認証時間は有効です。

Akshay Dhalwalaが言うように、サーバー側のシークレットが侵害された場合、攻撃者が内部ネットワークやソースコードリポジトリ、またはその両方を侵害したことになるため、対処すべき大きな問題があります。

ただし、侵害されたサーバーシークレットの被害を軽減し、ソースコードにシークレットを保存しないシステムには、 https://zookeeper.Apache.org のような調整サービスを使用したトークンシークレットローテーションが含まれます。 cronジョブを使用して、数時間ごとに(ただし、アクセストークンの有効期間)アプリシークレットを生成し、更新されたシークレットをZookeeperにプッシュします。トークンシークレットを知る必要がある各アプリケーションサーバーで、ZKノード値が変更されるたびに更新されるZKクライアントを構成します。プライマリシークレットとセカンダリシークレットを保存し、トークンシークレットが変更されるたびに、新しいトークンシークレットをプライマリに、古いトークンシークレットをセカンダリに設定します。このように、既存の有効なトークンは、セカンダリシークレットに対して検証されるため、依然として有効です。セカンダリシークレットが古いプライマリシークレットに置き換えられるまでに、セカンダリシークレットで発行されたアクセストークンはすべて期限切れになります。

3
skeller88

IETFのoAuthワーキンググループでRFCが進行中です: https://tools.ietf.org/id/draft-ietf-oauth-jwt-bcp-05.html =

0
SPoint