JWT — 読めるのに偽造できない通行証
ログイン後、サーバーは「この人はaliceさん」と毎回データベースに問い合わせる代わりに、本人だと証明する通行証を発行して持たせることがあります。その代表が JWT(JSON Web Token)。中身(誰なのか・権限は何か)が誰でも読めるのに、1文字でも書き換えると無効になるという不思議なチケットです。
秘密は末尾の署名(ハンコ)にあります。サーバーだけが知る秘密鍵で「ヘッダー+中身」からハンコを計算してくっつける。受け取ったサーバーは同じ計算をやり直し、ハンコが一致するか確かめます。下の図1で中身を書き換えてから検証してみてください。ハンコが合わなくなってブブーと弾かれます。
ヘッダー.中身.署名 の3つを . で繋いだ文字列server-secret-keyなぜ「読めるのに偽造できない」のか
JWTの中身は単にBase64でエンコードしただけで、暗号化はされていません。だから誰でもデコードして読めます(パスワードなど秘密を入れてはいけないのはこのため)。守っているのは署名です。署名は「ヘッダー+中身+秘密鍵」を HMAC-SHA256 などのハッシュにかけた値。秘密鍵を知らない攻撃者は、中身を書き換えてもそれに合う新しいハンコを計算できません。だから検証側で「中身から計算し直したハンコ」と「付いてきたハンコ」がズレ、改ざんが即バレます。
この仕組みのおかげで、サーバーはトークンをその場で検証するだけで本人確認でき、セッション情報をサーバー側に溜め込まなくて済みます(ステートレス)。一方で、一度発行したトークンは有効期限が来るまで取り消しにくい弱点もあります。だから exp(失効時刻)を短めにし、必要なら別途失効リストで管理します。
- JWT
- ヘッダー・中身・署名の3部をドットで繋いだ通行証。中身は読めるが改ざんは検知できる。
- 署名(HMAC)
- 秘密鍵を混ぜて計算するハンコ。鍵を知らないと正しい値を作れない。
- ステートレス
- サーバーが個別のセッションを保持せず、トークン自体で本人確認できる方式。
- exp(有効期限)
- トークンの失効時刻。盗まれたときの被害を抑えるため短めにするのが定石。
まとめ
JWTは「中身は公開、ハンコは秘密鍵で」という割り切りで成り立つ通行証です。中身を1文字でも書き換えるとハンコが合わなくなり、秘密鍵を持たない攻撃者は正しいハンコを作れない —— だから読めても偽造はできません。図1で role を admin に改ざんしてから検証し、サーバーが偽造を見抜く瞬間を確かめてみてください。