概要
JWT(JSON Web Token、RFC 7519)は、当事者間で安全にクレーム(主張情報)をやり取りするためのコンパクトなトークン形式です。OAuth 2.0のIDトークンや、独自APIのアクセストークンとして広く利用されます。JWTの本質は「署名によって改ざんを検知できる自己完結型のデータ構造」であり、サーバ側にセッション状態を保持しないステートレス認証を実現します。SC試験ではJWTそのものの構造理解に加え、署名アルゴリズムの選択ミスや検証不備を突く攻撃(alg:none攻撃、鍵混同攻撃)が頻出テーマです。
仕組みと動作原理
JWTの3要素構造
JWTは Header.Payload.Signature の3部分をピリオドで連結し、それぞれをBase64URLエンコードした文字列です。
| 要素 | 内容 | 例 |
|---|---|---|
| Header | 署名アルゴリズム(alg)とトークン種別(typ)を含むJSON | {"alg":"RS256","typ":"JWT"} |
| Payload | クレーム(ユーザ情報・有効期限等)を含むJSON。署名されるが暗号化はされない | {"sub":"1234","exp":1735689600} |
| Signature | HeaderとPayloadを結合した文字列に対する署名値 | 秘密鍵/共通鍵で生成 |
重要:Payloadは単なるBase64URLエンコードであり暗号化ではないため、誰でもデコードして中身を読めます。機密情報(パスワード等)をPayloadに含めてはいけません。
標準クレーム
| クレーム | 意味 |
|---|---|
iss(Issuer) | 発行者 |
sub(Subject) | トークンの主体(通常はユーザID) |
aud(Audience) | 想定される受信者 |
exp(Expiration Time) | 有効期限(UNIX時間) |
iat(Issued At) | 発行日時 |
jti(JWT ID) | トークンの一意識別子(失効管理・リプレイ防止に利用) |
署名アルゴリズムの選択:HS256 vs RS256
JWTの署名方式は大きく共通鍵方式と公開鍵方式に分かれ、システム構成によって適切な選択が異なります。
| 観点 | HS256(HMAC-SHA256、共通鍵) | RS256(RSA-SHA256、公開鍵) |
|---|---|---|
| 鍵の種類 | 発行・検証で同一の秘密鍵を共有 | 発行は秘密鍵、検証は公開鍵 |
| 適した構成 | 発行者と検証者が同一・信頼できる単一システム | 発行者と検証者が別サービス(マイクロサービス、外部連携) |
| 鍵の配布 | 秘密鍵自体を検証側にも配布する必要がある(漏えいリスク) | 公開鍵は自由に配布可能。秘密鍵は発行者のみが保持 |
| 検証側での偽造リスク | 検証用の鍵で署名も可能なため、検証側が偽造できてしまう | 検証側は公開鍵しか持たないため偽造不可 |
| 処理コスト | 軽量・高速 | 相対的に重い(非対称暗号演算) |
検証フロー
受信側は署名を検証してから初めてクレームを信頼してよい、という原則が重要です。
alg:none攻撃と鍵混同攻撃
JWTライブラリの実装不備を突く代表的な攻撃です。
| 攻撃 | 手口 | 対策 |
|---|---|---|
| alg:none攻撃 | Headerのalgをnoneに書き換え、署名を空にしたトークンを送信。検証側がalgをトークンの自己申告どおりに信用すると、署名検証をスキップしてしまう | サーバ側で許容するアルゴリズムをホワイトリストとして固定し、トークンのalg値を信用しない |
| アルゴリズム混同攻撃(鍵混同攻撃) | RS256運用のシステムに対し、HeaderをHS256に書き換え、本来公開されているRSA公開鍵をHMACの共通鍵として使って署名を偽造する | 検証時に鍵の種類とアルゴリズムの組み合わせを厳格にチェックし、公開鍵をHMAC鍵として誤用できないよう実装を分離する |
トークンの有効期限設計とリフレッシュトークン
JWTはステートレスであるがゆえに、発行後の失効が原則できません(サーバ側にセッション状態がないため)。この特性を踏まえた期限設計が重要です。
| トークン種別 | 推奨有効期限 | 保管場所の指針 |
|---|---|---|
| アクセストークン(JWT) | 短命(数分〜1時間程度) | メモリ上(画面遷移で消える程度)に保持し、漏えい時の被害を時間で限定 |
| リフレッシュトークン | 長命(数日〜数週間) | HttpOnly・Secure属性付きCookie等、JavaScriptから読み取れない領域に保管 |
リフレッシュトークン安全管理の要点:
- リフレッシュトークンローテーション:使用のたびに新しいリフレッシュトークンを発行し、古いものを無効化する。同一トークンの再利用を検知したら窃取を疑いトークンチェーン全体を失効させる
- サーバ側での失効管理:リフレッシュトークン自体はDBで状態管理し、ログアウト時やインシデント時に即座に無効化できるようにする(アクセストークンより長命なため、失効の仕組みが特に重要)
- XSS・CSRF双方への配慮:HttpOnly CookieはXSSからは守れるがCSRF対策は別途必要(SameSite属性等)
ステートレス認証のメリット・デメリット
| 観点 | メリット | デメリット |
|---|---|---|
| スケーラビリティ | サーバ側にセッションを持たないため水平スケールが容易 | — |
| サービス間連携 | マイクロサービス間で署名検証のみで認可判断が可能 | — |
| 即時失効 | — | 発行済みトークンを個別に無効化する標準機構がない(有効期限が来るまで有効) |
| トークンサイズ | — | セッションIDに比べペイロードが大きく、リクエストごとの通信量が増える |
| 情報露出 | — | Payloadは非暗号化のため、機密情報を含めると漏えいリスクになる |
SC試験での頻出ポイント
- JWTのPayloadは暗号化されていない:署名により改ざん検知はできるが、内容の秘匿はできない点が繰り返し出題される
- HS256とRS256の使い分け:単一システム内はHS256、発行者と検証者が異なる構成ではRS256(またはES256等の公開鍵方式)を選ぶ理由
- alg:none攻撃の原理:検証側が
algヘッダをクライアント入力のまま信用すると署名検証を回避されること - アクセストークンとリフレッシュトークンの役割分担:短命トークンで被害を限定し、長命トークンは失効管理を強化するという設計思想
- JWTの即時失効の困難さ:ステートレスゆえにログアウト即時反映が難しく、ブラックリストやリフレッシュトークンのDB管理で補う必要がある
よくある誤問・ひっかけパターン
誤り① 「JWTのPayloadは暗号化されているので機密情報を入れてもよい」→ 誤。PayloadはBase64URLエンコードのみで暗号化ではなく、誰でもデコードして中身を読めます。機密情報の格納は避けるべきです。
誤り② 「署名アルゴリズムはトークンのHeaderに書かれた値を使って検証すればよい」→ 誤。攻撃者がHeaderのalgをnoneや別方式に書き換えて署名検証を回避・偽造できるため、検証側は自身が期待するアルゴリズムをサーバ側で固定し、トークンの自己申告を信用してはいけません(alg:none攻撃・鍵混同攻撃)。
誤り③ 「JWTを使えばログアウト時に即座にトークンを無効化できる」→ 誤。JWTはステートレスな仕組みのため発行済みトークンを個別に失効させる標準機能はなく、有効期限を短く設定する、またはサーバ側でブラックリスト・リフレッシュトークンの状態管理を別途実装する必要があります。
関連用語
- OAuth 2.0とOIDC — OIDCのIDトークンはJWT形式で発行される代表例
- 暗号学的ハッシュ関数 — HS256で使われるHMAC-SHA256の基礎
- RSA暗号 — RS256の署名検証を支える公開鍵暗号方式
- セッション管理とCORS — トークンの保管場所(Cookie/localStorage)選択に関わるセキュリティ設計
重要キーワード
| 用語 | 説明 |
|---|---|
| JWT | Header.Payload.Signatureの3要素からなる自己完結型トークン形式(RFC 7519) |
| HS256 | HMAC-SHA256による共通鍵署名方式。発行者=検証者の構成に適する |
| RS256 | RSA-SHA256による公開鍵署名方式。発行者と検証者が分離した構成に適する |
| alg:none攻撃 | Headerのalgをnoneに書き換え署名検証を回避させる攻撃 |
| リフレッシュトークンローテーション | 使用のたびに新トークンを発行し再利用を検知する安全管理手法 |
| ステートレス認証 | サーバ側にセッション状態を持たず、トークン自体の検証のみで認可判断する方式 |