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