JWT入門から実務まで:基本構造・クレーム・署名・セキュリティ対策
はじめに — JWT とは何か
JWT(JSON Web Token)は、JSON 形式のクレーム(情報)を安全に表現・送受信するための標準フォーマットです。主に認証・認可や情報の伝達に使われ、「署名」により改ざん検知を可能にしたコンパクトなトークンとして広く利用されています。正式仕様は IETF の RFC 7519 に定められ、JOSE(JWS/JWE/JWK など)の枠組みの一部として設計されています。
基本構造
JWT は「ヘッダー . ペイロード . 署名」の3つの部分からなります。各部分は Base64url エンコードされ、ピリオド(.)で連結されます。
- ヘッダー(Header):トークンのタイプ(通常は "JWT")と署名アルゴリズム(例:"HS256", "RS256")を含む JSON。
- ペイロード(Payload):クレーム(claims)と呼ばれる利用者やトークンに関する情報を表す JSON。(iss, sub, aud, exp など)
- 署名(Signature):ヘッダーとペイロードを結合して署名アルゴリズムで生成した署名。改ざん検知と発行者の検証に使用。
簡単な例
概念をつかみやすくするための単純化した例(説明用であり実際の値は短縮しています):
ヘッダー(JSON):
{"alg":"HS256","typ":"JWT"}
ペイロード(JSON):
{"sub":"1234567890","name":"Taro Yamada","iat":1516239022,"exp":1516242622}
トークン例:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlRhcm8gWWFtYWRhIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1MTYyNDI2MjJ9.
<署名>
よく使われるクレーム(登録済みクレーム)
- iss:発行者(issuer)
- sub:主体(subject)— 一般的にユーザーIDなど
- aud:受信者(audience)— このトークンが想定される受け手
- exp:有効期限(expiration time)— UNIX 時刻で表現
- nbf:利用開始時刻(not before)
- iat:発行時刻(issued at)
- jti:一意なトークン識別子(JWT ID)
これらの登録済みクレームに加えて、独自のカスタムクレームを追加することも可能です。
署名アルゴリズムと暗号化
JWT 自体は署名(JWS: JSON Web Signature)により整合性と発行者の認証を提供します。主なアルゴリズムは:
- HS256(HMAC + SHA-256):対称鍵方式。発行側と検証側が同じ秘密鍵を共有する場合に使います。
- RS256(RSASSA-PKCS1-v1_5 + SHA-256):公開鍵暗号方式。発行側は秘密鍵で署名し、検証側は公開鍵で検証します。公開APIなどに向く。
- ES256(ECDSA + SHA-256):楕円曲線署名。短い鍵長で高い安全性。
トークンの暗号化(機密性確保)が必要な場合は、JWE(JSON Web Encryption)を使って暗号化された JWT をやり取りします。多くの実装では、署名(JWS)だけで十分なケースが多いですが、ペイロードに機密情報を入れるべきではありません。
利用シナリオ
- シングルページアプリ(SPA)やモバイルアプリでの認証・認可(Bearer トークンとして Authorization ヘッダに設定)
- マイクロサービス間の認証情報伝搬(トークンにユーザーやスコープ情報を含めることで、状態を持たない認可判断が可能)
- OAuth 2.0 のアクセストークンや OpenID Connect の ID トークンとしての利用(ただしアクセストークンが JWT とは限らない)
セキュリティ上の注意点(重要)
JWT は便利ですが、誤った実装や運用で重大な脆弱性を招くことがあります。代表的な注意点を挙げます。
- 署名を検証すること:受信したトークンは必ず署名検証を行い、発行者(iss)や受信者(aud)をチェックすること。
- アルゴリズムの固定化:トークンのヘッダーで指定された alg を鵜呑みにせず、サーバ側で許可するアルゴリズムを明示的に制限する("alg":"none" 攻撃やアルゴリズム切替攻撃を防ぐ)。
- 機密情報をペイロードに入れない:ペイロードは Base64url エンコードされるだけで暗号化されない。誰でもデコード可能なので、パスワードや機密データは入れない。
- HTTPS を必須にする:JWT は Bearer トークンとして扱われるため、盗聴で容易に悪用される。常に TLS(HTTPS)で送信する。
- 有効期限と短い寿命:アクセストークンの寿命を短く設定し、長期的なセッション管理にはリフレッシュトークンと組み合わせる。リフレッシュトークンはより厳重に保護する。
- トークンの取り消し(リボーク):JWT はステートレスであるため、発行後の取り消しが困難。必要ならブラックリスト(DB)やトークンID(jti)を使った照会、または短期間有効+リフレッシュで対処。
- 保存場所のリスク:ブラウザでは localStorage に保存すると XSS に弱い。セキュアな HttpOnly Cookie(SameSite)を使う、もしくは適切な CSRF 対策を行う。
- キー管理:秘密鍵や共有鍵のローテーション、保護が重要。公開鍵を配る場合は JWKs エンドポイント(公開鍵の JSON 形式)を使って動的に取得・検証することが推奨される。
実運用でのベストプラクティス
- 短いアクセストークンの有効期限(例:数分〜数時間)と、より慎重に管理されたリフレッシュトークンを組み合わせる。
- 署名検証時に iss, aud, exp, nbf, iat を必ずチェックし、時計のずれを考慮したスキュー(例:数十秒〜数分)を許容する。
- 公開鍵方式(RS256 など)を可能な限り採用し、API 側は署名検証のみで済ませられるようにする。キーは kid を使って識別・ローテーションする。
- トークンのリボークが必要な場合は、jti を DB に保存してブラックリストチェック、またはトークンインテロスペクション(OAuth 2.0 の仕様)を導入する。
- CORS/CSRF/XSS 対策を怠らない。SPA でのトークン保存は特に慎重に。
- ペイロードには最小限の情報のみを入れ、センシティブなデータはサーバ側で管理する。
よくある誤解・落とし穴
- 「JWT は盗まれても安全」ではない:JWT は有効期限中は Bearer トークンとして扱われ、持っているだけでアクセス可能。
- 「署名された=機密性がある」ではない:署名は改ざん検知のみで、暗号化(JWE)されていなければ内容は平文同様に見える。
- 「アクセストークンは常に JWT」ではない:OAuth2 のアクセストークンは実装により任意で、必ずしも JWT とは限らない。サービスによっては不透明(opaque)なトークンを返す。
まとめ
JWT は、スケーラブルでステートレスなトークンベースの認証・認可を実現する強力なツールです。正しく実装すればマイクロサービスやモバイル/SPA における認証基盤をシンプルにできます。一方で、署名検証、アルゴリズムの扱い、保存場所、鍵管理、トークンリボークの運用など、注意すべき点も多く、セキュリティ設計を怠ると大きなリスクを招きます。実装時は公式仕様(RFC)や OWASP のガイドライン、最新のベストプラクティスを参照し、安全な運用を心がけてください。
参考文献
- RFC 7519 — JSON Web Token (JWT)
- RFC 7515 — JSON Web Signature (JWS)
- RFC 7516 — JSON Web Encryption (JWE)
- RFC 7517 — JSON Web Key (JWK)
- OWASP — JSON Web Token Cheat Sheet
- Auth0: What is a JSON Web Token? (解説記事)
- OpenID Connect Core 1.0
- RFC 6749 — OAuth 2.0 Authorization Framework


