SheepDev

ハッシュ・ID・乱数

JWTの期限や中身を確認したい。何が分かる?

使うツール

APIが401を返すと、トークンの期限を疑いたくなります。しかし、JWTの中に書かれた日時だけを見て『まだ有効なのにサーバーがおかしい』と結論づけることはできません。期限は検証条件の一つであり、署名、発行者、受け取り先なども別に確認されるからです。ここでは、秘密を含まない架空のJWTを使い、まず時刻の読み方を整理します。実際の認証情報を記事の例や問い合わせへ貼り付ける必要はありません。

三つの区切りではなく、三つの部分

JWTデコードへ次の文字列を入力します。二つのピリオドでHeader・Payload・Signatureの三つに分かれています。これはalgがnoneで署名部分が空の、説明専用の例です。ログインには使えません。ツールはHeaderとPayloadをBase64urlから復元してJSONとして読みますが、この例を含め、表示できたトークンを信頼できるものとは扱いません。

署名のない架空の説明用JWT
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJkZW1vLXVzZXIiLCJpYXQiOjE3MDQwNjcyMDAsIm5iZiI6MTcwNDA2NzIwMCwiZXhwIjoxNzA0MDcwODAwfQ.

実際のJWTにはユーザー識別子や権限などが入っている場合があります。Base64urlは暗号化ではないので、署名が付いていてもPayloadは読めます。トークンを入手した人が内容を読めることと、その人が内容を改変して認証を通せることは別です。署名検証は後者に関係しますが、このデコード画面では実施しません。

exp・nbf・iatは、それぞれ何の時刻か

例のiatとnbfは1704067200で、UTCの2024年1月1日00:00:00です。expは1704070800で、一時間後の01:00:00です。iatは発行時刻、nbfはそれより前に受け入れない時刻、expは期限を表します。発行時刻があるからといって有効期間が一律に一時間とは限りません。今回は例としてそう設定しているだけです。

この例のUTC時刻
iat = nbf = 2024-01-01T00:00:00Z
exp       = 2024-01-01T01:00:00Z

JWTのNumericDateはUnix時間の秒を基準にします。JavaScriptのDate.now()が返すミリ秒を、そのままexpへ入れると意味が変わります。桁数を眺めて直すのではなく、生成側が何の単位を渡しているか確認し、Unix時間変換で秒として照合します。JSONの文字列として書かれた日時と数値のClaimも同じではありません。この画面の時刻解析は数値のClaimを対象にしています。

端末時計と、検証サーバーの時計は別

ツールは端末の現在時刻と比較して、時刻が過去か未来かの参考情報を出します。たとえば例のexpちょうどでは期限を過ぎた側になります。しかし、実際のサーバーが使う時刻、許容する時計のずれ、認証ライブラリの設定はここから分かりません。端末の時計が遅れていれば、画面ではまだ未来でもサーバーでは期限を過ぎている場合があります。

『日本時間ではまだ今日』という判断も期限確認には不十分です。UTCの01:00は日本時間の10:00ですが、同じ瞬間を表しています。表示Timezoneを変えても寿命は延びません。問い合わせへ時刻を示すなら、UTCまたはUTCオフセットを添え、ブラウザーで見た時刻なのかサーバーログなのかも分けます。なお、このツールはサーバーへ問い合わせて時計を取得する機能ではありません。

期限を変えて読めても、認証は直らない

Payloadのexpを未来へ書き換えて再エンコードすれば、デコード画面には未来の日時を表示できます。しかし、署名付きJWTでは署名対象の内容が変わるため、元の署名とは整合しなくなります。認証側は適切な検証を必要とします。『デコード成功』や『時刻が未来』という結果を、認証の成功と取り違えないでください。画面の署名未検証表示は、この区別のためにあります。

issやaudが表示されても、そのサービスが本当に発行したか、今のAPIが対象かをツールが確認したわけではありません。Headerのalgも入力内容であり、信頼できる設定ではありません。鍵を取りに外部へ接続したり、認証サーバーへ照会したりしない設計なので、調査の次の段階は認証側の設定とログです。そこで必要な情報も、トークン全文ではなく最小限の識別情報や時刻に整理します。

読めないときに、無理にJWTへ直さない

この画面は三部構成のJWTを対象にします。五部構成の暗号化されたJWEの復号や、サービス独自の不透明なトークンには対応しません。区切りを削除して三つにしたり、エラーが消えるまで文字を落としたりすると、元の情報を調べていることになりません。まずコピー範囲、前後の引用符、AuthorizationヘッダーのBearerという接頭辞を確認し、トークン本体だけを扱います。

調査が終わったら、『expはUTCでいつ、端末時計との差はどうか、署名はこの画面では未検証』と整理できます。Claimがない場合も、存在しない期限を勝手に補いません。入力と結果を自動保存しない画面であっても、画面共有、スクリーンショット、クリップボードから認証情報が漏れる可能性は別です。記事の架空例で操作を確かめ、実データは組織の取り扱い方針に従ってください。

Payloadのroleがadminでも、管理者だとは確認できない

PayloadへroleやuserIdが入っていると、その文字列が本当の利用者情報に見えるかもしれません。しかし、この画面はトークン内の値を読んでいるだけです。誰が発行したか、想定した相手向けか、署名が正しいか、利用者の権限が今も有効かは確かめていません。expが未来であることも、それらの代わりにはなりません。表示できた内容をデバッグの手掛かりにすることと、その内容を信頼してアクセスを許可することを明確に分けます。

認証エラーの調査では、まず失敗した処理がどのトークンを使ったかを確認します。以前の画面で取得した別のトークンを貼って未来のexpを見ても、失敗したリクエストの期限切れを否定できません。ブラウザーの時刻表示、送信されたトークン、サーバー側の判定時刻を同じ調査対象としてそろえる必要があります。ここへ実トークンを貼る必要がある場合も、共有画面やコピーした文字列に認証情報が残ることへ注意し、公開のバグ報告には実値を載せないようにします。

調査の結論は『この端末の現在時刻ではexpを過ぎている』『nbfより前に見える』『三部構成として解析できない』のように、確認した事実の範囲で書きます。『有効なJWT』という言葉は署名や用途の検証まで済んだように読めるため、このデコード結果だけには使いません。期限の値を変えて読めるようになった場合も、実際に署名された元のトークンを修正したことにはならず、認証処理で受け入れられるかは別です。

参考資料

使うツール

使い方・解説 →