メインコンテンツまでスキップ

RFC 7519: JSON Web Token(JWT)

RFC 7519 は、JSON 形式でクレーム(主張)を表現するためのトークン仕様です。このドキュメントでは、JWT の構造と使用方法を解説します。


第1部: 概要編

JWT とは何か?

JWT(JSON Web Token、ジョットと読む)は、2 者間で情報を安全にやり取りするためのコンパクトで URL セーフなトークン形式です。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
└─────────────┬─────────────┘.└───────────────────────────┬───────────────────────────┘.└──────────────────┬──────────────────┘
Header Payload Signature

JWT の用途

用途説明
アクセストークンOAuth 2.0 のアクセストークンとして使用
ID トークンOpenID Connect でユーザー情報を伝達
クライアント認証private_key_jwt / client_secret_jwt
情報交換サービス間で署名付きデータをやり取り

JWT の特徴

特徴説明
コンパクトBase64URL エンコードで URL やヘッダーに含めやすい
自己完結トークン自体に必要な情報が含まれる
検証可能署名により改ざんを検知できる
暗号化可能JWE を使えば内容を秘匿できる

第2部: 詳細編

JWT の構造

JWT は 3 つのパートをドット(.)で連結した文字列です。

Header.Payload.Signature

Header(ヘッダー)

トークンのメタデータ。署名アルゴリズムとトークンタイプを指定。

{
"alg": "RS256",
"typ": "JWT",
"kid": "key-id-123"
}
フィールド必須説明
alg署名アルゴリズム(HS256, RS256, ES256 など)
typトークンタイプ(通常 "JWT")
kid鍵 ID(複数鍵がある場合に使用)

Payload(ペイロード)

クレーム(主張)のセット。ユーザー情報やトークンのメタデータを含む。

{
"iss": "https://auth.example.com",
"sub": "user-123",
"aud": "https://api.example.com",
"exp": 1704070800,
"iat": 1704067200,
"nbf": 1704067200,
"jti": "unique-token-id"
}

Signature(署名)

ヘッダーとペイロードを署名したもの。改ざん検知に使用。

RSASHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
privateKey
)

登録済みクレーム(Registered Claims)

RFC 7519 で定義されている標準クレーム。

クレーム名前説明
issIssuerトークン発行者
subSubjectトークンの主体(ユーザー ID など)
audAudienceトークンの対象者(受信者)
expExpiration Time有効期限(Unix タイムスタンプ)
nbfNot Before有効開始時刻
iatIssued At発行時刻
jtiJWT IDトークンの一意識別子

すべて任意だが、用途に応じて必須になる。

公開クレーム(Public Claims)

IANA に登録されているか、衝突回避のために URI 形式で定義されるクレーム。

{
"https://example.com/claims/role": "admin",
"email": "user@example.com",
"name": "John Doe"
}

プライベートクレーム(Private Claims)

発行者と受信者の間で合意されたカスタムクレーム。

{
"department": "engineering",
"employee_id": "EMP-12345"
}

署名アルゴリズム

アルゴリズム種類用途
HS256HMAC共有秘密シンプルな用途
HS384HMAC共有秘密
HS512HMAC共有秘密
RS256RSA公開鍵/秘密鍵一般的な用途
RS384RSA公開鍵/秘密鍵
RS512RSA公開鍵/秘密鍵
ES256ECDSA公開鍵/秘密鍵コンパクト
ES384ECDSA公開鍵/秘密鍵
ES512ECDSA公開鍵/秘密鍵
PS256RSA-PSS公開鍵/秘密鍵より安全な RSA
noneなし-使用禁止

JWT の検証

検証時に確認すべき項目:

1. 署名検証
└── 公開鍵または共有秘密で署名を検証

2. 構造検証
└── 3 パートに分割できるか
└── 各パートが有効な Base64URL か
└── ペイロードが有効な JSON か

3. クレーム検証
├── exp: 現在時刻 < exp(有効期限内か)
├── nbf: 現在時刻 >= nbf(有効開始時刻を過ぎているか)
├── iat: 発行時刻が妥当か
├── iss: 期待する発行者か
├── aud: 自分が対象者に含まれているか
└── その他のビジネスロジック

JWT vs JWS vs JWE

用語説明
JWTクレームを表現するトークン形式
JWS署名付きデータの形式(JWT の署名に使用)
JWE暗号化データの形式(JWT の暗号化に使用)
JWT は JWS または JWE を使って実装される

署名付き JWT:
JWT → JWS 形式 → Header.Payload.Signature

暗号化 JWT:
JWT → JWE 形式 → Header.EncryptedKey.IV.Ciphertext.Tag

署名 + 暗号化:
JWT → JWS → JWE(Nested JWT)

セキュリティ考慮事項

項目推奨事項
alg: none絶対に受け入れない
署名検証必ず行う。スキップしない
有効期限短く設定(アクセストークンは数分〜数時間)
機密情報ペイロードに含めない(Base64 はエンコードであり暗号化ではない)
鍵管理秘密鍵は安全に保管。定期的にローテーション
aud 検証必ず行う。別サービス向けトークンの誤用を防ぐ

よくある脆弱性

1. alg: none 攻撃

// 攻撃者が送信
{
"alg": "none",
"typ": "JWT"
}

// 対策: alg のホワイトリストを使用
Set<String> allowedAlgorithms = Set.of("RS256", "ES256");
if (!allowedAlgorithms.contains(header.getAlgorithm())) {
throw new Exception("Algorithm not allowed");
}

2. 鍵混同攻撃

攻撃者が RS256 → HS256 に変更し、
公開鍵を HMAC の秘密鍵として使用させる

対策: 鍵タイプとアルゴリズムの整合性を確認

3. 署名検証スキップ

// 危険なコード
JWTClaimsSet claims = SignedJWT.parse(token).getJWTClaimsSet();
// 署名検証していない!

// 安全なコード
SignedJWT jwt = SignedJWT.parse(token);
if (!jwt.verify(verifier)) {
throw new Exception("Invalid signature");
}
JWTClaimsSet claims = jwt.getJWTClaimsSet();

参考リンク