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


111

(これは実際には独自の問題であり、NodeJSなどに固有ではないため、このスレッドから生成されます

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

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

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

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

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

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

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

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

サーバーシークレットが危険にさらされるリスクに関しては、私は単に過度に偏執的であるかもしれません。もちろん、これは、すべての暗号化の状況で対処する必要があるより一般的な問題です...


1
すばらしい質問があります。再:質問2。サーバー側に保持されている秘密鍵についても同じ問題があります。ハッシュ照合または非対称復号化を実行している場合、これがjwtに署名する場合でも、dbに格納されているcc情報を復号化する場合でも、サーバー上のコードからアクセスできる秘密鍵が必要です。地獄はどこに保管しますか?これが私が見つけた最良の答えです:pcinetwork.org/forum/index.php?threads / -おそらくjwtキーでも同じくらい安全です。
jbd 2016年

jwtトークンの秘密鍵とは何ですか?私はjwtトークン自体を秘密だと思っています。または秘密鍵はRSAPrivateKey privateKey??
kittu

3
これは少し前に尋ねられましたが、多分誰かがそれが役に立つと思うでしょう。私の場合、ユーザーごとに「秘密鍵」を持っています。したがって、ユーザーがログインするたびに、シークレットを生成し、ユーザーレコードとともにDBに保存します。その秘密を使用してトークンを検証します。ログアウト時に、その値をクリアします。これにより、以前に作成された他のトークンが自動的に無効になります(これが私が必要とするものです)。
ネルソンロドリゲス

回答:


52

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

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

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

あなたの質問のために:

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

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


5
ここで第二の点に関しては良い答えは次のとおりです。security.stackexchange.com/questions/87130/...
Bossliaw

1
トークンはヘッダーで使用できるので、トークンが盗まれて悪意のあるユーザーがそのトークンでログインしようとした場合(ユーザーの電子メールアドレスを知っている場合)はどうなりますか?
kittu

22
すべてのJWTを格納する場合、JWTにメリットはなく、ランダムなセッションIDを使用することもできます。
ColinM

46

アプリケーションにJWTを実装する際に考慮すべき点は次のとおりです。

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

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

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

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

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

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

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

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

1
あなたが何を参照してcreated_byいるか、JWTにはすでにその要求があり、それはiss(発行者)と呼ばれています。
フレッド

ええ良い点-私はそれで更新します...ありがとう!
Brad Parks、

8

私は専門家ではないと思いますが、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にリンクされています。:私はランダム変数と混合された秘密を持っています。シークレットはトークンごとに一意です。

ただし、本当に安全なシステムを作成するために、トークンを検証する方法と範囲を正確に確認するためのベストプラクティスを理解しようとしています。

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


すべてのトークンに一意のシークレットを設定するのは良い点ですが、毎回どのようにして一意のシークレットを作成しますか?私はニンバスjwtライブラリを使用しています
kittu

1
おそらくユーザーのハッシュパスワードを使用してください。
momokjaaaaa

1
「他の人と同じように物事を行っていない場合、他の人があなたのセキュリティを介して方法を見つけるのはより困難になります。」これは、私にはあいまいさによるセキュリティのように聞こえます。ベストプラクティスと呼ばれるのは、最も一般的なリスクを実際的な方法で軽減するためです。
Mnebuerquo 2017年

@Mnebuerquo私はあなたに完全に同意します、それを書いた人は信頼すべきではありません;-)
デブラトンジャンフィリップ

1
彼は正解ですが、盲目的にベストプラクティスに従うべきではありません。ベストプラクティスが最良と見なされる理由を理解することは良いことです。すべてのセキュリティ設計の決定において、セキュリティとユーザビリティの間にはトレードオフがあります。理由を理解することは、それらの決定をインテリジェントに行うことができることを意味します。(ただし、ユーザーが参加しないため、ベストプラクティスに従ってください。)
Mnebuerquo

3

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

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

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

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

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

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

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

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


0

IETFはoAuthワーキンググループで進行中のRFCを持っています:https ://tools.ietf.org/id/draft-ietf-oauth-jwt-bcp-05.html

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.