( このスレッド から生成されます。これは実際にはNodeJSなどに固有ではなく独自の問題であるため)
認証付きのREST APIサーバーを実装しています。ユーザーがJWTトークンを生成するために、ユーザーがユーザー名/パスワードを使用して/ loginエンドポイントからログインできるように、JWTトークン処理を正常に実装しました。サーバーシークレットとクライアントに返されます。次に、トークンは、認証された各APIリクエストでクライアントからサーバーに渡され、サーバーシークレットがトークンの検証に使用されます。
しかし、真に安全なシステムを作成するために、トークンを検証する方法と程度を正確に示すためのベストプラクティスを理解しようとしています。トークンの「検証」に関与する必要があるのは正確に何ですか?サーバーシークレットを使用して署名を検証できれば十分ですか、それともトークンやトークンペイロードをサーバーに保存されているデータと照合する必要がありますか?
トークンベースの認証システムは、ユーザーのパスワードを取得するよりもトークンを取得することが同等以上に難しい場合に限り、各リクエストでユーザー名/パスワードを渡すのと同じくらい安全です。ただし、私が見た例では、トークンを生成するために必要な情報は、ユーザー名とサーバー側の秘密だけです。これは、悪意のあるユーザーがサーバーシークレットの知識を得ると1分間仮定すると、anyユーザーに代わってトークンを生成できるようになることを意味しませんか?これにより、パスワードが取得された場合のように特定の1人のユーザーだけでなく、実際にはallユーザーアカウントにアクセスできますか?
これは私に質問をもたらします:
1)JWTトークンの検証は、トークン自体の署名の検証、サーバーシークレットの整合性のみに依存する、または別の検証メカニズムを伴うことに限定する必要がありますか?
場合によっては、/ loginエンドポイントからのログインに成功するとセッションが確立されるトークンとサーバーセッションを組み合わせて使用することがあります。 APIリクエストはトークンを検証し、トークンで見つかったデコードされたデータをセッションに保存されたデータと比較します。ただし、セッションを使用することはCookieを使用することを意味し、ある意味ではトークンベースのアプローチを使用する目的に反します。また、特定のクライアントに問題を引き起こす可能性があります。
サーバーが現在使用中のすべてのトークンをmemcacheなどで保持していると想像できます。これにより、サーバーのシークレットが侵害され、攻撃者が「有効な」トークンを生成できる場合でも、/ loginエンドポイントから生成された正確なトークンのみが生成されます受け入れられます。これは合理的ですか、それとも単なる冗長/過剰ですか?
2)JWT署名検証がトークンを検証する唯一の手段である場合、つまりサーバーシークレットの整合性がブレークポイントである場合、サーバーシークレットをどのように管理する必要がありますか?環境変数から読み取り、デプロイされたスタックごとに1回作成(ランダム化?)しますか?定期的に更新またはローテーションします(ローテーション前に作成されたが、ローテーション後に検証する必要がある既存の有効なトークンの処理方法。サーバーが特定の時点で現在および以前のシークレットを保持している場合は、おそらくそれで十分です) ?他に何か?
サーバーの秘密が危険にさらされるというリスクに関しては、私は単に過度に妄想的です。これはもちろん、すべての暗号化状況で対処する必要があるより一般的な問題です...
私も自分のアプリケーションのトークンで遊んでいます。私は決して専門家ではありませんが、この問題に関する私の経験や考えの一部を共有できます。
JWTのポイントは、本質的に整合性です。これは、サーバーに提供されたトークンが本物であり、サーバーによって提供されたことをサーバーが検証するメカニズムを提供します。あなたの秘密を介して生成された署名は、これを提供するものです。ですから、はい、あなたの秘密が何らかの形で漏洩した場合、その個人はあなたのサーバーがそれ自身だと思うトークンを生成できます。トークンベースのシステムは、単に署名の検証のために、ユーザー名/パスワードシステムよりも安全です。この場合、誰かがあなたの秘密を持っている場合、システムには、偽のトークンを作成する誰かよりも対処すべきセキュリティ上の問題があります(さらに、秘密を変更するだけで、古い秘密で作成されたトークンは無効になります)。
ペイロードに関しては、署名は、提供されたトークンがサーバーが送信したときとまったく同じであったことを通知するだけです。ペイロードの内容がアプリケーションにとって有効または適切であることを検証するのは、明らかにあなた次第です。
ご質問:
1.)私の限られた経験では、2番目のシステムでトークンを検証する方が間違いなく優れています。署名を検証するだけで、トークンがあなたの秘密で生成されたことを意味します。作成されたトークンを何らかのDB(redis、memcache/sql/mongo、またはその他のストレージ)に保存することは、サーバーが作成したトークンのみを受け入れることを保証する素晴らしい方法です。このシナリオでは、たとえ秘密が漏洩したとしても、生成されたトークンはいずれにしても有効ではないので、それほど重要ではありません。これは私のシステムで取っているアプローチです-生成されたすべてのトークンはDB(redis)に保存され、リクエストごとに、トークンを受け入れる前にDBにあることを確認します。このようにして、何らかの理由でトークンを取り消すことができます。たとえば、何らかの形で野生にリリースされたトークン、ユーザーのログアウト、パスワードの変更、シークレットの変更などです。
2.)これは私があまり経験がないものであり、セキュリティの専門家ではないので、私はまだ積極的に研究しているものです。リソースを見つけたら、ここに投稿してください!現在、私は単にディスクからロードする秘密鍵を使用していますが、明らかにそれは最良または最も安全なソリューションとはほど遠いです。
アプリケーションに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の実装を検討してください。
すべてのJWT認証の失敗は、JWT認証が失敗した理由を示す「エラー」応答ヘッダーを生成する必要があります。例えば「期限切れ」、「使用法はありません」、「失効」など。これにより、実装者はJWTが失敗する理由を知ることができます。
JWTが情報を漏らし、ハッカーに制御の尺度を与えるため、JWTの「ヘッダー」を無視することを検討してください。これは主にヘッダーのalg
フィールドに関するものです-これを無視し、ヘッダーがサポートしたいものであると想定してください。これは、ハッカーがNone
アルゴリズムを使用して署名セキュリティチェックを削除するのを防ぐためです。
JWTには、どのアプリがトークンを生成したかを詳述する識別子を含める必要があります。たとえば、2つの異なるクライアントmychatとmyclassifiedsappによってJWTが作成されている場合、それぞれにプロジェクト名またはJWTの「iss」フィールドに類似したものを含める必要があります。 「iss」:「mychat」
iat
(有効期限)の代わりにexp
(発行日)の使用を強く検討してください。どうして? iat
は基本的にJWTがいつ作成されたかを意味するため、作成日に基づいてJWTの有効期限が切れたときにサーバー上で調整できます。誰かが将来20年後のexp
を渡すと、JWTは基本的に永遠に生き続けます! iat
が将来的な場合はJWTを自動的に期限切れにしますが、クライアントの時間がサーバーの時間とわずかに同期していない場合に備えて、少しのゆらぎ(10秒など)を考慮してください。/mysite/userInfo?jwt=XXX
、およびこのURLがキャッシュされること。彼らはログアウトし、数分後、通常のユーザーがアプリにログインします。キャッシュされたコンテンツを取得します-スーパーユーザーに関する情報が含まれています!これは、特にAkamaiのようなCDNを使用しており、一部のファイルの寿命を延ばす場合に、クライアントでは少なく、サーバーではより多く発生する傾向があります。これは、関連するユーザー情報をURLに含め、サーバー上でこれを検証することで修正できます。たとえば、/mysite/userInfo?id=52&jwt=XXX
私は専門家だとは思いませんが、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)。このハッカーは、両方の情報を同時に取得します。
私がそれを処理する方法は、ポイント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クライアントを構成します。プライマリシークレットとセカンダリシークレットを保存し、トークンシークレットが変更されるたびに、新しいトークンシークレットをプライマリに、古いトークンシークレットをセカンダリに設定します。このように、既存の有効なトークンは、セカンダリシークレットに対して検証されるため、依然として有効です。セカンダリシークレットが古いプライマリシークレットに置き換えられるまでに、セカンダリシークレットで発行されたアクセストークンはすべて期限切れになります。
IETFのoAuthワーキンググループでRFCが進行中です: https://tools.ietf.org/id/draft-ietf-oauth-jwt-bcp-05.html =