RFC 7519 - JSON Web Token (JWT)
概要
RFC 7519 は、JSON Web Token(JWT) を定義する標準仕様である。JWT は、2つの当事者間でクレーム(claims)をコンパクトかつ URL-safe な方法で表現・転送するためのメカニズムを提供する。
HTTP ヘッダや URI クエリパラメータなど、スペースに制約のある環境での使用を想定して設計されており、クレームは JSON オブジェクトとして表現され、JSON Web Signature(JWS)によるデジタル署名・MAC、または JSON Web Encryption(JWE)による暗号化によって保護される。
解決する課題
JWT 以前は、セキュリティトークンの標準形式として SAML(Security Assertion Markup Language)や SWT(Simple Web Token)が使われていた。しかし以下の課題があった。
- SAML の冗長性: XML ベースで構造が複雑・サイズが大きく、HTTP ヘッダや URI での使用に適さない
- SWT の表現力の乏しさ: 型付けされた値や複雑なデータ構造を表現できない
- 相互運用性の欠如: 統一された標準がなく実装間での互換性が低い
JWT は JSON のシンプルさとコンパクト性を活かし、特に OAuth 2.0 などの Web 系プロトコルでの利用に最適化されたトークン形式を提供する。
主要概念・用語
| 用語 | 説明 |
|---|---|
| JWT | JSON Web Token。クレームセットを表現するコンパクトな URL-safe トークン |
| クレーム(Claim) | エンティティ(通常はユーザー)や追加情報に関する主張 |
| JWT クレームセット | クレームを含む JSON オブジェクト |
| JOSE ヘッダー | 暗号化操作に関するメタデータを含む JSON オブジェクト |
| JWS | JSON Web Signature。JWT を署名・MAC で保護する仕様(RFC 7515) |
| JWE | JSON Web Encryption。JWT を暗号化で保護する仕様(RFC 7516) |
| NumericDate | 1970-01-01T00:00:00Z UTC からの経過秒数を表す JSON 数値 |
| StringOrURI | 文字列、またはコロン(:)を含む場合は URI として解釈される値 |
| Unsecured JWT | アルゴリズムに "none" を指定した署名なし JWT |
JWT の構造
JWT は Base64url エンコードされた 3 つの部分をピリオド(.)で連結した形式を取る。
BASE64URL(JOSE ヘッダー) . BASE64URL(ペイロード) . BASE64URL(署名)具体例
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5cJOSE ヘッダー
暗号化操作のメタデータを含む JSON オブジェクト。
{
"alg": "HS256",
"typ": "JWT"
}主要なパラメータ:
| パラメータ | 説明 |
|---|---|
alg | 使用する署名・暗号化アルゴリズム(必須) |
typ | メディアタイプ。JWT には "JWT" を推奨 |
cty | コンテンツタイプ。Nested JWT の場合は "JWT" を指定 |
ペイロード(JWT クレームセット)
クレームを含む JSON オブジェクト。クレームは「登録済みクレーム名」「パブリッククレーム名」「プライベートクレーム名」の 3 種類に分類される。
{
"iss": "https://example.com",
"sub": "user123",
"aud": "https://api.example.com",
"exp": 1735689600,
"iat": 1735686000,
"jti": "abc123"
}署名
JWS の場合、JOSE ヘッダーとペイロードに対して指定されたアルゴリズムで計算した値。JWE の場合は暗号化された内容となる。
クレームの詳細
登録済みクレーム名
IANA に登録された標準クレーム。いずれもオプションだが、使用する場合は定義に従った意味を持つ。
| クレーム | 名称 | 型 | 説明 |
|---|---|---|---|
iss | Issuer | StringOrURI | JWT を発行したプリンシパルの識別子 |
sub | Subject | StringOrURI | JWT の主体(ユーザー等)の識別子。発行者のコンテキスト内で一意 |
aud | Audience | StringOrURI または配列 | JWT の受信対象。処理するシステムは自身が対象か確認する |
exp | Expiration Time | NumericDate | この時刻以降は JWT を受け付けない(有効期限) |
nbf | Not Before | NumericDate | この時刻より前は JWT を受け付けない(有効開始時刻) |
iat | Issued At | NumericDate | JWT の発行時刻。年齢の判定に使用可能 |
jti | JWT ID | 文字列 | JWT の一意識別子。リプレイ攻撃の防止に使用 |
パブリッククレーム名
独自に定義できるが、衝突を防ぐため IANA「JSON Web Token Claims」レジストリへの登録、またはドメイン名・OID・UUID などのコリジョン耐性のある名前の使用が求められる。
プライベートクレーム名
発行者と受信者の間で独自に定義するクレーム。名前衝突のリスクがあるため、外部との共有には注意が必要。
プロトコルフロー
JWT の生成と検証フロー
JWT の作成手順(Section 7.1)
- JWT クレームセットを含む JSON オブジェクトを作成する
- その UTF-8 表現をメッセージとして準備する
- JOSE ヘッダーを作成する(JWS または JWE の仕様に従う)
- JWS または JWE として処理する
- ネストが必要な場合は手順 3 に戻り、新しい JOSE ヘッダーで
"cty": "JWT"を指定する - 最終的な JWT を取得する
JWT の検証手順(Section 7.2)
- JWT が少なくとも 1 つのピリオド(
.)を含むことを確認する - JOSE ヘッダーを Base64url デコードし、有効な JSON であることを確認する
- JOSE ヘッダーのパラメータを検証する
- JWS か JWE かを判定する(
"enc"パラメータの有無で識別) - 該当する仕様に従い署名の検証または復号を行う
- ネストされた JWT の場合は再帰的に処理する
- ペイロードを Base64url デコードし、有効な JSON であることを確認する
exp・nbf・iss・aud等の登録済みクレームを検証する
詳細解説
JWS vs JWE
JWT は保護方式によって 2 つの形態がある。
| 種別 | 特徴 | ヘッダー例 |
|---|---|---|
| JWS | 署名・MAC による完全性保護。ペイロードは Base64url されているだけで可読 | {"alg":"HS256"} |
| JWE | ペイロードを暗号化。機密情報の保護が可能 | {"alg":"RSA-OAEP","enc":"A256GCM"} |
| Nested JWT | JWS を JWE で包む。署名のプライバシーも保護 | {"alg":"RSA-OAEP","enc":"A256GCM","cty":"JWT"} |
Unsecured JWT
アルゴリズムに "none" を指定した場合、署名なしの JWT となる。JWT 外部のセキュリティ機構(TLS など)によって保護されている場合に使用される。
{
"alg": "none"
}この形式は署名値が空文字列となり、トークンの末尾のピリオドの後に何も付かない。実装では "none" の受け入れを適切に制限する必要がある。
NumericDate の扱い
有効期限などの時刻値は NumericDate(UNIX エポックからの経過秒数)で表現する。うるう秒は考慮しない。
exp: 1735689600 → 2026-01-01T00:00:00Zクレームの複製(JWE での特殊ケース)
JWE(暗号化 JWT)において、iss・sub・aud のクレームを JOSE ヘッダーに複製することが許可されている。これにより、復号前にこれらのクレームを確認できる。ただし、ヘッダー内の値とペイロード内の値の一致を必ず検証しなければならない。
必須・推奨アルゴリズム
RFC 7519 では以下のアルゴリズムサポートを規定している(詳細は RFC 7518 / JWA を参照)。
| アルゴリズム | 種別 | 要件 |
|---|---|---|
HS256(HMAC + SHA-256) | JWS | 必須(MUST) |
none | JWS(Unsecured) | 必須(MUST) |
RS256(RSASSA-PKCS1-v1_5 + SHA-256) | JWS | 推奨(RECOMMENDED) |
ES256(ECDSA + P-256 + SHA-256) | JWS | 推奨(RECOMMENDED) |
セキュリティに関する考慮事項
信頼の確立
JWT の内容を信頼決定に使用するためには、暗号学的に保護されており、かつその保護に使用されたキーが正当な発行者の制御下にあることを確認する必要がある。署名検証に使用するキーの出所の確認が不可欠である。
アルゴリズムの混同攻撃(Algorithm Confusion)
検証側が期待するアルゴリズムを明示的に指定せず、ヘッダーの alg パラメータをそのまま使用すると、攻撃者が意図しないアルゴリズムで署名を検証させる「アルゴリズム混同攻撃」が発生する可能性がある。
例:RS256 で署名を検証するシステムに対し、公開鍵を HMAC の共有鍵として使い "alg":"HS256" のトークンを送りつける攻撃。
対策:検証側は許可するアルゴリズムを事前に設定し、ヘッダーの値に関わらずそれを使用する。
"none" アルゴリズムの取り扱い
Unsecured JWT("alg":"none")を意図せず受け入れる実装が存在すると、署名検証をバイパスされる危険がある。"none" を受け入れる場面を明示的に制限する必要がある。
署名と暗号化の順序
機密性と完全性の両方が必要な場合は、署名してから暗号化する(Sign then Encrypt) 順序が推奨される。これにより:
- 暗号化によって署名者の身元が保護される
- 暗号文の外側からは署名者情報が漏洩しない
有効期限の検証
exp・nbf の検証は必須である。クロックスキュー(サーバー間の時刻のずれ)を考慮した若干のマージン(数分程度)を設けることが一般的だが、マージンは最小限に留めるべきである。
jti によるリプレイ攻撃対策
一度使用した jti を記録し、同じ jti を持つ JWT を拒否することでリプレイ攻撃を防ぐことができる。ステートレスな JWT の利点を損なうが、高セキュリティな場面では有効な対策となる。
機密クレームの保護
署名のみの JWS では、ペイロードは誰でも読める(Base64url は暗号化ではない)。個人情報や機密情報を含む場合は、JWE による暗号化が必要である。
関連仕様
| 仕様 | 内容 |
|---|---|
| RFC 7515 - JWS | JSON Web Signature。JWT の署名・MAC 処理の基盤 |
| RFC 7516 - JWE | JSON Web Encryption。JWT の暗号化処理の基盤 |
| RFC 7517 - JWK | JSON Web Key。JWT の署名・暗号化に使用する鍵の表現形式 |
| RFC 7518 - JWA | JSON Web Algorithms。JWT で使用可能なアルゴリズムの定義 |
| RFC 6749 - OAuth 2.0 | JWT はアクセストークンやアサーションとして OAuth 2.0 と組み合わせて広く使われる |
| RFC 9068 | JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens |
| OpenID Connect Core | ID トークンとして JWT を使用 |