私はJWTが大好きです。一緒に仕事をするのは本当に楽しいです。私の質問はこれです:私がJWTを取得して、私がペイロードをデコードすることができるならば、それはどのように安全ですか?ヘッダからトークンを取り出し、ペイロード内のユーザ情報をデコードして変更し、同じ正しいエンコードされたシークレットを使用して送り返すことはできませんか。
私はそれらが安全でなければならないことを知っています、しかし私は本当に技術を理解したいです。何が足りないの?ありがとうございます。
JWTは、署名付き、暗号化、またはその両方のいずれかです。トークンが署名されているが暗号化されていない場合は、誰でもそのトークンの内容を読むことができますが、秘密鍵がわからない場合は変更できません。そうでなければ、受信者は署名がもう一致しないことに気付くでしょう。
あなたのコメントに答える:私はあなたのコメントが正しい方法で理解されているかどうかわからない。念のために:デジタル署名を知っていて理解していますか? 1つの変種(対称型ですが、他にもたくさんあります)について簡単に説明します。
アリスがJWTをボブに送ろうとしているとしましょう。二人とも共有の秘密を知っています。 Malloryはその秘密を知りませんが、JWTを妨害して変更したいと考えています。それを防ぐために、AliceはHash(payload + secret)
を計算し、これを署名として追加します。
メッセージを受信すると、BobはHash(payload + secret)
を計算して署名が一致するかどうかを確認することもできます。ただし、Malloryがコンテンツの内容を変更した場合、一致する署名を計算することはできません(これはHash(newContent + secret)
になります)。彼女はその秘密を知りませんし、それを見つける方法もありません。これは、彼女が何かを変更した場合、署名が一致しなくなり、Bobが単にJWTを受け入れなくなることを意味します。
別の人に{"id":1}
というメッセージを送り、Hash(content + secret)
でそれに署名します。 (+はここでの単なる連結です)。私はSHA256ハッシュ関数を使用しています、そして私が得る署名は330e7b0775561c6e95797d4dd306a150046e239986f0a1373230fda0235bda8c
です。マロリーの役を演じ、メッセージ{"id":2}
に署名してみてください。私がどの秘密を使ったのかわからないからできない。受信者がその秘密を知っていると仮定すれば、彼はあらゆるメッセージの署名を計算し、それが正しいかどうかをチェックすることができます。
jwt.io
に行き、トークンを貼り付けて内容を読むことができます。これは当初、多くの人にとって不快なことです。
簡単な答えは、JWTは暗号化には関係ないということです。検証を気にかけます。つまり、「このトークンの内容を操作してもらう」という答えを常に得ることができるのですか。これは、サーバーがトークンを認識して無視するため、ユーザーがJWTトークンを操作しても無駄であることを意味します。サーバーは、クライアントにトークンを発行するときにペイロードに基づいて署名を追加します。後でそれはペイロードと一致する署名を検証します。
論理的な問題は、暗号化されたコンテンツに関係しないという動機は何ですか?
最も簡単な理由は、これが大部分解決された問題であると想定しているからです。たとえば、Webブラウザのようなクライアントを扱う場合は、JWTトークンをsecure + httpsOnly
(Javascriptでは読み取れません+ HTTPでは読み取れません)で、暗号化されたチャネルを介してサーバーと通信するCookieに格納できます。 (HTTPS)サーバーとクライアントの間に安全なチャネルがあることがわかったら、JWTなどを安全に交換できます。
これは物事をシンプルに保ちます。単純な実装は採用を容易にしますが、それはまた各層がそれが最善を尽くすことを可能にします(HTTPSに暗号化を処理させます)。
JWTは機密データを保存することを目的としていません。サーバーがJWTトークンを受信してそれを検証すると、そのユーザーに関する追加情報(許可、住所など)について、独自のデータベースでユーザーIDを自由に検索できます。これにより、JWTのサイズを小さく保ち、機密データをJWTに保存しないことを誰もが知っているので、不用意な情報漏洩を防ぎます。
クッキー自体がどのように機能するかとそれほど変わりはありません。クッキーはしばしば暗号化されていないペイロードを含んでいます。あなたがHTTPSを使用しているならば、それからすべてが良いです。そうでなければそれはそれ自身敏感なクッキーを暗号化することをお勧めします。そうしないと、中間者攻撃が可能になります。つまり、プロキシサーバーまたはISPがCookieを読み取り、後であなたになりすましてCookieを再生します。同様の理由で、JWTは常にHTTPSのような安全な層を介して交換されるべきです。
JSON Webトークン(JWT)の内容は本質的に安全ではありませんが、トークンの信頼性を検証するための組み込み機能があります。 JWTは、ピリオドで区切られた3つのハッシュです。三つ目は署名です。公開鍵/秘密鍵システムでは、発行者は、対応する公開鍵でしか検証できない秘密鍵を使用してトークン署名に署名します。
発行者と検証者の違いを理解することが重要です。トークンの受信者はそれを検証する責任があります。
WebアプリケーションでJWTを安全に使用するには、2つの重要なステップがあります。1)それらを暗号化されたチャネルで送信すること、および2)署名を受信したらすぐに検証することです。公開鍵暗号方式の非対称性により、JWT署名検証が可能になります。公開鍵は、JWTがそれに一致する秘密鍵によって署名されたことを検証します。他のキーの組み合わせでこの検証を行うことはできないため、偽装の試みを防ぐことができます。これら二つのステップに従ってください、そして我々は数学的確実性でJWTの信憑性を保証することができます。
続きを読む: 公開鍵はどのように署名を検証しますか?
サーバー上にあるJWTのprivateKeyのみが暗号化されたJWTを復号化します。 privateKeyを知っている人は、暗号化されたJWTを復号化することができます。
サーバーの安全な場所にprivateKeyを隠して、だれにもprivateKeyを教えないでください。
私のように高価なデータベースクエリを購入できない人にとって、機密データ(ユーザーの特権など)を保持する1つのオプションは、JWTを生成するときにこのデータを暗号化してJWTトークンに添付することです。 (バックエンドで暗号化キーを保持します)
機密情報を読み取りたい場合は、JWTトークンをバックエンドに送信して解読し、情報を取得できます。このようにして、DBルックアップを実行したり、JWTトークンを介してフロントエンドで機密情報を裸にする必要はありません。
私は復号化するためにjwt.ioに存在しない特別なアルゴリズムを使ってJWEを調べることを提案するでしょう
参照リンク: https://www.npmjs.com/package/node-webtokens
jwt.generate('PBES2-HS512+A256KW', 'A256GCM', payload, pwd, (error, token) => {
jwt.parse(token).verify(pwd, (error, parsedToken) => {
// other statements
});
});
この答えは遅すぎるかもしれませんし、あるいはあなたがすでに道を見つけたかもしれませんが、それでも、私はそれがあなたと他の人たちにも同様に役に立つだろうと感じました。
私が作成した簡単な例: https://github.com/hansiemithun/jwe-example