「ログイン後にサーバが渡す“署名付きの通行証”」——それがJWTです。仕組みと、安全に使うための勘所を解説します(攻撃手順は載せません)。
仕組み(3つの部分)
JWTは ヘッダ.ペイロード.署名 の3つを . でつないだ文字列です。ヘッダとペイロードはbase64urlでエンコードされているだけ(暗号化ではない)で、署名だけが秘密鍵(または共有鍵)で作られます。
① ヘッダ
署名アルゴリズム等のメタ情報。誰でも読める
② ペイロード
利用者IDや有効期限などの主張。誰でも読める=秘密を入れない
③ 署名
鍵で生成。改ざんされていないことを保証
中身が「読めるだけ」なのが肝心です。だからペイロードはパスワードや個人情報を入れる場所ではありません。JWTの価値は、サーバが署名を検証することで「このトークンは自分が発行し、改ざんされていない」と確認できる点にあります。
安全に使うための防御
署名を必ず検証し、algを固定する(最重要)
サーバ側で署名を毎回検証する。受け入れる署名アルゴリズム(alg)を期待する値に固定し、alg:none(署名なし)は拒否する。トークンのヘッダに書かれたalgを鵜呑みにしない。JWTのベストプラクティス(RFC 8725)は、ライブラリは呼び出し側が許可アルゴリズムの集合を指定できるようにしなければならず、それ以外は使ってはならないとしています。またJWT中のすべての暗号処理を検証し、1つでも失敗したらJWT全体を拒否しなければならないと定めています。
「alg:none」だけでなく“すり替え”も塞ぐ
alg の悪用は署名を消すことだけではありません。RFC 8725 は、RS256 を HS256 に書き換えられると、一部のライブラリが「RSA公開鍵をHMACの共有鍵として」署名を検証しようとすると説明しています(アルゴリズム混同)。公開鍵は誰でも入手できるので、これが通ると攻撃者が自分で有効な署名を作れてしまいます。防ぎ方は同じ一点に尽きます——ヘッダの alg を信用せず、サーバ側が期待するアルゴリズムを固定する。鍵の種類ごとに検証関数を選ぶのではなく、アルゴリズムを先に決めてから検証するのが正しい順番です。
「誰宛て・いつまで」まで検証する
署名が正しいことは「本物である」ことしか示しません。それが自分宛てで、まだ有効かは別の検証です。RFC 7519 は aud(宛先)について「受け取った側が aud の値に自分を認めないなら、そのJWTは拒否しなければならない」、exp について「その時刻以降は処理のために受け入れてはならない」と定めています(nbf も同様に「その時刻より前は受け入れてはならない」)。RFC 8725 はさらに、発行者(iss)と鍵の対応を検証することを求めています。別サービス向けに正しく発行されたトークンが自分のところで通ってしまう事故は、この検証を飛ばしたときに起きます。
ペイロードに秘密を入れない
中身は誰でもデコードできる前提。パスワード・個人情報・APIキーなどの秘密は入れない。入れるのは識別子や権限など、漏れても致命的でない主張だけにする。
有効期限を短くし、失効の手段を持つ
アクセス用トークンは短命にする。長すぎる有効期限は、盗まれたときの被害時間を延ばす。失効が必要な設計なら、短命アクセストークン+サーバ側で管理するリフレッシュ/セッションを併用する。
強い鍵を使い、盗まれない場所に置く
署名鍵は十分に強く、使い回さず、サーバ側の安全な場所に保管する。トークン自体も、XSSで盗まれない・安全な属性のCookieで運ぶなど、保管と運搬を含めて守る(→ XSS 経由の窃取に注意)。
当サイトの視点:JWTは“万能のセッション”ではない
JWTはよく「ログイン状態の保存」に使われますが、失効が苦手という弱点があります。署名が正しく期限内なら、サーバは基本的にそれを信じるため、ログアウトや無効化を即時に効かせにくいのです。当サイトの立場は、「JWTを長命の万能セッションにしない」こと。短命のアクセストークンと、サーバ側で取り消せるリフレッシュ/セッションを組み合わせれば、JWTの利点(検証が軽い)と失効のしやすさを両立できます。用途を選ぶのが正解です。
盲点:「デコードできた」は「正しい」ではない
JWTは中身が読めるので、JWTデコーダに貼れば誰でもヘッダとペイロードを確認できます。ただしデコード(中身を読む)と検証(本物か確かめる)はまったくの別物です。デコードできることは正しさを何も保証しません。トークンが本物かを決めるのは、必ずサーバ側の署名検証です。デバッグで中身を見るのは便利ですが、「読めたから有効」と勘違いしないでください。
出典(一次情報)
- IETF RFC 8725「JSON Web Token Best Current Practices」 — datatracker.ietf.org(アルゴリズムの固定・すべての暗号処理の検証・アルゴリズム混同・発行者と鍵の対応)
- IETF RFC 7519「JSON Web Token (JWT)」 — datatracker.ietf.org(
exp/nbf/audの規範的な定義)
次に読む
- ツール:JWTデコーダ / 検査(中身の確認・alg:noneや期限切れの点検)
- 設計:パスワードリセットの設計欠陥(トークンを発行する側の落とし穴)
- 用語:XSS とは(トークン窃取の典型経路)/ CSRF とは
- 入門:二要素認証(MFA)の選び方
よくある質問
QJWTの中身は暗号化されていますか?
いいえ。標準的なJWTのヘッダとペイロードは暗号化ではなくbase64urlで“エンコード”されているだけで、トークンを持っている人は誰でも中身を読めます。だからパスワードや個人情報などの秘密をペイロードに入れてはいけません。JWTが守るのは『中身の秘匿』ではなく『改ざんされていないこと(署名による完全性)』です。
QJWTで一番危険な設定は何ですか?
署名を検証しない、または『alg:none(署名なし)』を受け入れてしまう実装です。これを許すと、攻撃者が中身を自由に書き換えた偽トークンを通せてしまいます。防御は、サーバ側で署名を必ず検証し、受け入れる署名アルゴリズム(alg)を期待する値に固定することです。
Qデコードと検証は同じですか?
違います。デコードは中身を読むだけで、誰でもできます(JWTデコーダで確認できます)。検証は、署名が正しいか・有効期限内か・発行者や対象が正しいかをサーバが秘密鍵/公開鍵で確かめる処理です。『デコードできた=正しいトークン』ではありません。本物かどうかを決めるのは必ずサーバ側の検証です。