JWT生成ツール

秘密鍵はこのページ内でのみ使用され、送信・保存もURLへの追加も行いません。そのため共有リンクから漏えいすることはありません。ただし本番用の署名鍵は当サイトを含めいかなるWebサイトにも貼り付けないでください。テストには使い捨ての鍵を使用してください。

対応しているのはHS256・HS384・HS512のみです。RS・ES・PSでの署名には秘密鍵が必要なため、本ツールでは意図的に扱いません。

入力した内容が保存・記録・共有されることはありません。

ペイロードを編集し、アルゴリズムを選んで秘密鍵で署名します。署名はすべてブラウザ内で行われるため、鍵が端末外に出ることはありません。

使い方

  1. ペイロードをJSONで編集します。
  2. 必要に応じて有効期限を選ぶと、iatとexpが自動で追加されます。
  3. 秘密鍵を入力すると、署名済みトークンが下に表示されます。

署名で生成されるもの

JWTは、3つのbase64urlセグメントをドットでつないだものです。1つ目はどのアルゴリズムを使ったかを示すヘッダー、2つ目はクレームを入れたペイロード、3つ目は最初の2つのセグメントをドットでつないだものに対して計算した署名です。署名されるのはそれらのセグメントの正確なバイト列であって、デコードした結果のJSONではありません。トークンを再シリアライズすると無効になるのはそのためです。

HS256の署名は、その署名対象に対する、秘密鍵を使ったHMACです。同じ秘密鍵を持つ人なら誰でも再計算して一致するかを確かめられ、それによって2つのことが証明されます。トークンが秘密鍵を知っている人によって発行されたこと、そしてその後に中身が一切変更されていないことです。ペイロードを1文字でも変えれば、再計算した署名は一致しなくなります。

一方で、署名は何も隠しません。ペイロードはエンコードされているだけで暗号化されておらず、トークンを持っている人なら秘密鍵なしですべてのクレームを読めます。パスワードやカード番号など、ログに出力したくないものは決してJWTのペイロードに入れないでください。

秘密鍵の選び方

RFC 7518は、HMACの鍵にハッシュ出力と同じ長さ以上を求めています。HS256なら256ビット、HS384なら384ビット、HS512なら512ビットです。つまり、覚えやすいフレーズではなく、最低でも32バイトのランダムな値が必要です。

理由は、JWTそのものがオフライン攻撃の材料一式だからです。トークンには署名対象と署名が一緒に入っているので、1つでも入手した人は、ネットワークの往復もレート制限もなく、ハードウェアが許す限りの速さで候補の秘密鍵を試せます。まさにそれを行うツールが公開されており、辞書に載っている単語や短い文字列なら数秒で破られます。弱い秘密鍵のトークンが漏れれば、攻撃者は好きなクレームを入れた自分用のトークンを発行できてしまいます。

パスワードマネージャーや鍵生成ツールで作ったランダムな値を使い、ステージングのトークンを本番で再利用されないよう環境ごとに別の秘密鍵を持ち、ほかの認証情報と同じようにローテーションしてください。

設定しておくべきクレーム

アプリケーションに必要なもののほかに、RFC 7519は少数の標準クレームを登録しています。iss は発行者、sub は主体、aud は想定される受信者を示し、jti はトークンに一意なIDを与えて、個別に失効させたり再利用を検出したりできるようにします。3つの時刻クレーム、有効期限の exp、有効になる最も早い時点の nbf、発行時刻の iat はNumericDate値、つまりUNIXエポックからの秒数です。

ミリ秒ではなく秒です。JavaScriptのタイムスタンプをそのまま渡してしまうのが、手書きのトークンが拒否される最も多い原因です。13桁の exp ははるか未来の日付として解釈され、そのまま拒否するライブラリもあれば、期限切れにならないトークンとして受け入れてしまうライブラリもあります。

exp を設定しただけでトークンが期限切れになるわけではありません。期限切れになるのは検証側がクレームを確認するからで、署名しか確認しない検証側は去年のトークンでも喜んで受け入れます。また、発行側と検証側のマシンの時計が完全に一致することはまれなので、多くのライブラリは通常1〜2分程度の時計のずれを許容します。

HS系アルゴリズムだけに対応する理由と、algの落とし穴

HS系は対称方式で、1つの共有秘密鍵で署名も検証も行うため、入力した情報だけでここで署名できます。RS、ES、PSは非対称方式で、秘密鍵をWebページに貼り付けてもらう必要があり、このツールはそれを求めるつもりはありません。

アルゴリズムを示すヘッダーのフィールドは、よく知られた2つの攻撃の舞台でもあります。1つ目は alg: none で、トークンが署名されていないことを宣言します。これを受け入れるライブラリには、署名が空の偽造トークンを渡せてしまいました。2つ目はアルゴリズムのすり替えです。RS256で署名されたトークンのヘッダーをHS256に書き換え、発行者の公開鍵をHMACの秘密鍵として署名します。あらかじめ決めておくのではなくトークンからアルゴリズムを読み取る検証側は、公開鍵は秘密ではないので、これを問題なく検証してしまいます。

どちらの防御策も同じで、発行側ではなく検証側に置くべきものです。検証の呼び出しで想定するアルゴリズムを固定し、ヘッダーがそれと一致しないトークンはすべて拒否してください。

トークンの寿命を設計する

トークンの仕組みで最も影響が大きい選択は、トークンをどれだけの期間有効にするかです。JWT は有効期限が切れるまで取り消せないからです。アクセストークンなら5分から15分という短い有効期間にしておけば、トークンが漏れたときの危険な時間帯を小さく抑えられます。これが標準的な答えで、サーバー側で保存しているため失効させられる、有効期間の長いリフレッシュトークンと組み合わせて使います。

リフレッシュトークンのローテーションを加えると、この組み合わせは実質的にかなり安全になります。リフレッシュのたびに新しいリフレッシュトークンを発行し、古いものを無効にするので、盗まれたトークンは一度しか使えません。古いトークンがもう一度提示されたら、同じトークンを二者が持っていることがサーバーにわかるので、その系統をまとめて失効させられます。

本当に長期間有効な資格情報が必要な場合、たとえばマシン間の連携や CLI などでは、JWT はたいてい適した形ではありません。データベースと照合する API キーなら即座に失効でき、権限も細かく絞れ、最後に使われた日時を持ち主が確認できる画面に表示することもできます。

鍵、ローテーション、そして kid ヘッダー

署名鍵はサービスを止めずに交換できるべきで、そのための仕組みが kid ヘッダーです。発行側がどの鍵で署名したかを示し、検証側は決め打ちせずにその鍵を引きます。HS256 なら鍵 ID からシークレットを引く小さなマップになり、RS256 や ES256 なら検証側が取得してキャッシュする JWKS ドキュメントになります。

ローテーションは3段階になります。まず新しい鍵を公開して検証側に知らせ、次に古い鍵も受け付けたまま署名を新しい鍵に切り替え、最後に古い鍵で署名したトークンがすべて期限切れになってから古い鍵を廃止します。この重なりの期間を省くことが、日常的なローテーションを障害に変えてしまうのです。

自分のトークンを検証するサービスが2つ以上になった時点で、非対称アルゴリズムは余分な準備の手間をかける価値があります。HS256 では検証側のすべてが署名にも使えるシークレットを持つため、どれか1つのサービスが侵害されればトークンを発行されてしまいます。RS256 なら検証側は公開鍵しか持たず、何も偽造できません。

ペイロードに入れてよいもの、いけないもの

トークンはリクエストのたびにヘッダーで運ばれる bearer 資格情報なので、サイズには実際のコストがあります。プロキシはヘッダーを 8 KB で打ち切ることが多く、肥大したトークンの代償は呼び出しのたびに払うことになります。中身は本人を表す情報と、検証側が必要とするわずかな事実だけに留めましょう。すなわち subject、issuer、audience、有効期限、そして少数のスコープやロールです。

変わりやすいものは向いていません。トークンに焼き込まれた権限は発行された瞬間から古くなっていくので、10:00 に剥奪したロールも、トークンが期限切れになるまで主張され続けます。それが問題になる場面では、トークンには本人を表す情報だけを載せてサービス側で認可を引くか、古さが許容できる程度に有効期間を短くすべきです。

秘密の情報はそもそも一切入れてはいけません。ペイロードはエンコードされているだけで暗号化はされていないため、トークンを持つ人は誰でもすべてのクレームを読めます。社内向けのメモも、受け取り側に必要な範囲を超えた個人情報も、鍵も入れないでください。どうしてもペイロードを秘匿する必要があるなら、それは JWE という別の仕様であり、扱うツールも別になります。

情報を漏らさずにトークンを試す

ジェネレーターが最も役に立つのはフィクスチャ作りです。期限切れのトークン、まだ有効になっていないトークン、audience が違うトークン、別の鍵で署名したトークン。検証処理はこの4つすべてに対してテストすべきで、この領域のバグはたいてい、そのどれかを受け入れてしまうというものです。

テスト用のシークレットを使い、本番のものは決して使わないでください。ほかの資格情報と同じ理屈ですが、ここではより切実です。トークンとその署名がそろえば、オフラインでシークレットを攻撃するには十分だからです。環境ごとにシークレットを分けておけば、ステージングで発行したトークンが本番でも通ってしまうという、より気づきにくい失敗も防げます。

このページの処理はすべてブラウザー内で動くので、ここに入力した内容が送信されたり保存されたりすることはありません。トークン系のツールに人が何を貼り付けるかを考えれば、これは知っておく価値があります。そして非対称アルゴリズムを用意していない理由もここにあります。RS256 で署名するには秘密鍵を Web ページに貼り付けることになり、そんなものを求めるツールがあってはならないからです。

手作りのトークンが弾かれるよくある理由

最も多いのは時刻のクレームをミリ秒で入れてしまうケースです。NumericDate はエポックからの秒数なので、13桁の exp は数万年先の日付として読まれます。そのまま拒否するライブラリもあれば、永久に有効なトークンとして受け入れるライブラリもあり、どちらも望んだ結果ではありません。

次に多いのがパディングです。JWT のセグメントはパディングなしの base64url を使うので、セグメントの末尾に等号が付いていたり、マイナスとアンダースコアの代わりにプラスとスラッシュが含まれていたりするトークンは、間違ったアルファベットでエンコードされており、署名の検証にたどり着く前に失敗します。

残りはたいてい不一致です。検証側が期待する audience が末尾のスラッシュ1つ分だけ違う、issuer が http で書かれているのに検証側は https を使っている、片方のマシンの時計が数分ずれているのにクロックスキューの許容が設定されていない、といったものです。デコードは正しくできるのに検証に失敗するときは、署名を疑う前に、クレームと検証側の設定をフィールドごとに突き合わせてください。

よくある質問

署名用の秘密鍵を入力しても安全ですか?
鍵はこのページ上のJavaScriptでのみ使用されます。送信・保存もURLへの書き込みも行わないため、リンクを共有しても漏えいしません。ただし本番の署名鍵はパスワードと同様に扱い、テストには使い捨ての値を使用してください。
なぜHS256・HS384・HS512のみ対応なのですか?
これらは共通鍵方式で、1つの鍵で署名と検証の両方を行えます。RS・ES・PSは公開鍵方式のため秘密鍵をWebフォームに貼り付ける必要があり、本ツールでは意図的にそれを求めません。
iatとexpにはどんな値を入れますか?
どちらもNumericDateで、ミリ秒ではなくUNIXエポックからの秒数です。ここで有効期限を選べば正しい形式で書き込まれます。ミリ秒で指定するのが、手書きトークンが拒否される最も多い原因です。
ヘッダーに独自のフィールドを追加できますか?
ヘッダーは選択したアルゴリズムとtyp: JWTに設定されます。kidなどの項目は個別の鍵管理方式に依存するため、実際のトークンを発行するライブラリ側で付与するのが適切です。
ここで生成したトークンを本番で使ってよいですか?
いいえ。これはテストとデバッグのためのツールです。実際のトークンは、鍵のローテーション・失効・クレーム検証を管理する認証サービスが発行すべきです。

最終更新:

問題を報告

操作手順、期待した結果、実際の結果を記載してください。秘密情報や個人情報は削除してください。

関連ツール