本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。
RFC 7519: JWT (JSON Web Token) の仕組みとプロトコル実装上の注意点
背景
現代のウェブアプリケーションやAPIエコシステムでは、ステートレスな認証・認可が求められることが多くなっています。特に、マイクロサービスアーキテクチャ、シングルページアプリケーション(SPA)、モバイルアプリケーションでは、異なるサービス間でユーザーのアイデンティティや権限情報を安全かつ効率的に伝達するメカニズムが必要です。従来のセッションベースの認証では、セッション情報のサーバーサイド管理が必須となり、水平スケーリングやクロスドメインでの利用に課題がありました。
設計目標
RFC 7519「JSON Web Token (JWT)」は、これらの課題を解決するために以下の設計目標を持って考案されました。
コンパクトさ: URL-safeな形式で、HTTPヘッダやクエリパラメータ、POSTパラメータとして簡単に送信できるサイズ。
自己完結性: トークン自体にユーザー情報や権限情報が含まれており、リソースサーバーが別途データベースを参照することなく、トークンの検証と認可判断が可能。
安全性: 署名または暗号化によって、トークンの完全性(Integrity)と機密性(Confidentiality)が保証される。これにより、トークンが改ざんされていないこと、および不正な傍受からの保護が実現される。
相互運用性: JSONベースの構造とBase64Urlエンコーディングを採用することで、異なるプログラミング言語やプラットフォーム間での容易な実装と利用が可能。
ステートレス性: サーバーサイドでセッション状態を保持する必要がなく、水平スケーリングを容易にする。
詳細
JWTは、JSON形式の情報を安全に表現するためのコンパクトなURI-safeな手段を提供します。JWTには主にJWS (JSON Web Signature) とJWE (JSON Web Encryption) の2つの形式があります。これらの詳細については、それぞれRFC 7515 (JWS) および RFC 7516 (JWE) で定義されています。
JWS (JSON Web Signature)
JWSは、デジタル署名またはMAC(Message Authentication Code)によってJWTの完全性を保証します。構造は以下の3つのコンポーネントをBase64Urlエンコードし、ドット . で連結したものです。
BASE64URL(JWS Header) . BASE64URL(JWS Payload) . BASE64URL(JWS Signature)
JWS Header 構造: JWS Headerは、トークンの署名アルゴリズムや鍵の種類などを記述するJSONオブジェクトです。
alg:string (Algorithm) - 署名アルゴリズム (例: HS256, RS256)。RFC 7518で定義。 typ:string (Type) - トークンのタイプ (通常は "JWT")。 kid:string (Key ID, optional) - 鍵を識別するためのID。RFC 7517で定義されたJWKと関連。
JWS Payload (Claims) 構造: JWS Payloadは、トークンが運ぶ情報を記述するJSONオブジェクトです。これらは「Claims」(クレーム)と呼ばれ、Registered Claims, Public Claims, Private Claimsの3種類があります。
iss:string (Issuer, optional) - 発行者 (例: "auth.example.com")。RFC 7519で定義。 sub:string (Subject, optional) - 主題 (ユーザーIDなど)。RFC 7519で定義。 aud:string (Audience, optional) - 受信者 (APIサービスなど)。RFC 7519で定義。 exp:number (Expiration Time) - 有効期限 (Unix時間)。RFC 7519で定義。 nbf:number (Not Before, optional) - 有効開始時刻 (Unix時間)。RFC 7519で定義。 iat:number (Issued At, optional) - 発行時刻 (Unix時間)。RFC 7519で定義。 jti:string (JWT ID, optional) - 一意のJWT識別子 (リプレイ攻撃対策に利用)。RFC 7519で定義。 custom_claim:any (Private Claims) - 任意のカスタム情報。
JWS Signature 構造:
HeaderとPayloadをBase64Urlエンコードし、ドットで連結した文字列 (BASE64URL(JWS Header) . BASE64URL(JWS Payload)) を指定されたアルゴリズムと鍵で署名した結果です。
JWE (JSON Web Encryption)
JWEは、JWTの機密性を保証するために、トークン全体を暗号化します。構造は以下の5つのコンポーネントをBase64Urlエンコードし、ドット . で連結したものです。
BASE64URL(JWE Header) . BASE64URL(JWE Encrypted Key) . BASE64URL(JWE IV) . BASE64URL(JWE Ciphertext) . BASE64URL(JWE Authentication Tag)
JWE Headerは暗号化アルゴリズムや鍵の管理方法などを指定し、Encrypted Keyは対称鍵暗号に使用する鍵を非対称鍵で暗号化したもの、IVは初期化ベクトル、Ciphertextは暗号化されたデータ、Authentication Tagは認証タグです。これにより、改ざん検出と機密保護が両立されます。
JWTの利用シーケンス
一般的なJWTの利用シーケンスは以下のようになります。
sequenceDiagram
participant C as クライアント
participant "AS as 認証サーバー (Auth Server)"
participant "RS as リソースサーバー (Resource Server)"
C ->> AS: 1. 認証リクエスト |ユーザー名/パスワード|
AS -->> C: 2. 認証成功 & JWT発行
Note right of AS: JWSを生成し、デジタル署名
(またはJWEで暗号化)
C ->> RS: 3. リソースリクエスト |AuthorizationヘッダにJWTを添付|
Note right of C: Authorization: Bearer
RS ->> RS: 4. JWTの検証 |署名検証, 有効期限チェックなど|
Note right of RS: ASの公開鍵で署名検証、クレーム検証
alt 検証成功
RS -->> C: 5. リソース提供
else 検証失敗
RS -->> C: 5. エラー応答 |例: 401 Unauthorized|
end
相互運用
JWTは、RFC 7519として標準化されており、関連するRFC 7515 (JWS), RFC 7516 (JWE), RFC 7517 (JWK), RFC 7518 (JWA) とともにエコシステムを形成しています。
OAuth 2.0 (RFC 6749): 認可フレームワークとしてOAuth 2.0が広く利用されていますが、そのアクセストークンやIDトークンの形式としてJWTが推奨されています。特にOpenID Connect (OIDC) Core 1.0ではIDトークンとしてJWTが必須です。
SAML (Security Assertion Markup Language): XMLベースの認証・認可プロトコルであるSAMLと比較して、JWTはJSONベースであるため、よりコンパクトでウェブ環境との親和性が高いです。SAMLはXML署名やXML暗号化を使用するため、処理が重くなる傾向があります。
セッションクッキー: サーバーサイドで状態を管理するセッションクッキーと比較して、JWTは自己完結型であり、サーバーが状態を持つ必要がないため、マイクロサービスやCDN利用時のスケーラビリティに優れます。ただし、セッションを強制的に無効化するログアウトなどの機能の実装がより複雑になります。
セキュリティ考慮
JWTの利用には以下のセキュリティ考慮事項が不可欠です。
リプレイ攻撃 (Replay Attacks): JWSは認証情報を含むため、傍受されたトークンが再利用されるリスクがあります。これを防ぐためには、
exp(Expiration Time) クレームによる有効期限の厳格なチェック、jti(JWT ID) クレームとサーバー側での使用済みトークンリスト(Allow/Deny List)の管理、またはOne-Time Nonceの利用が有効です。署名アルゴリズムのダウングレード攻撃 (Algorithm Downgrade Attacks): JWS Headerの
algパラメータを攻撃者が変更し、より脆弱なアルゴリズムや署名検証をスキップさせる(例:alg: "none") アルゴリズムの使用を強制する試みです。実装は、信頼できるアルゴリズムのホワイトリストを保持し、受信したJWTのalgクレームがそのホワイトリストに含まれているかを確認する必要があります。特に、"none"アルゴリズムの使用は明示的に拒否するべきです。鍵更新と鍵管理 (Key Rotation and Management): 署名鍵や暗号化鍵は定期的に更新(ローテーション)されるべきです。JWK Set (JSON Web Key Set, RFC 7517) を利用することで、公開鍵の配布と管理を効率的に行えます。鍵の漏洩が発生した場合に備え、迅速な鍵無効化と再発行のプロセスが必要です。
0-RTTの再送リスク (0-RTT Replay Risk): TLS 1.3 (RFC 8446) の0-RTTモードでJWTを含むリクエストを送信する際、リクエストが再送されるリスクがあります。0-RTTで送信されるデータは、暗号化されていてもリプレイ攻撃に対して脆弱であるため、冪等ではない操作(ユーザーのパスワード変更など)にJWTを使用する場合は、注意が必要です。0-RTTを許可しない、またはリプレイが許容される操作に限定するといった対策が必要です。
情報漏洩: JWSのPayloadはBase64Urlエンコードされるだけであり、暗号化はされません。機密情報を含める場合は、JWEを使用して暗号化する必要があります。
実装メモ
ネットワークエンジニアとしてJWTを実装または運用する際に考慮すべき点を挙げます。
MTU/Path MTU (Maximum Transmission Unit / Path MTU Discovery): JWTはHTTPヘッダの
Authorizationフィールドなどに挿入されて送信されます。JWTのサイズが大きすぎると、HTTPリクエストのヘッダサイズが増加し、基盤となるTCP/IPパケットがMTUを超える可能性があります。これにより、IPフラグメント化が発生し、ネットワーク機器の負荷増大やパケットロスのリスクが高まります。Path MTU Discovery (PMTUD) が適切に動作しない環境では、通信障害の原因となることもあります。JWTのペイロードは必要最小限に抑え、大規模なデータを運ぶ際にはJWTではなく、参照渡し(JWTにはIDのみを含み、実際のデータは別途APIで取得)を検討すべきです。HTTP/2 (RFC 7540) とヘッダ圧縮: HTTP/2ではHPACK (RFC 7541) によるヘッダ圧縮が行われますが、頻繁に変わるJWTは圧縮効率が低下する可能性があります。HTTP/3 (RFC 9114) ではQPACKによる圧縮が導入されており、この点も考慮されます。特に、多数のカスタムクレームを含む大きなJWTは、継続的に送信されるとネットワーク帯域を消費し、効率を低下させる可能性があります。
HOL blocking回避とキュー制御: JWT自体が直接HOL (Head-of-Line) blockingを引き起こすわけではありませんが、JWTの検証処理が遅延すると、アプリケーション層でリクエスト処理のボトルネックとなる可能性があります。リソースサーバーはJWTの検証を高速に行うためのキャッシュメカニズム(公開鍵のキャッシュなど)や、適切な非同期処理・キューイングにより、リクエストの並列処理とスループットの維持を図るべきです。
優先度: 認証・認可に関わるJWTの検証は、セキュリティ上、そしてアプリケーションの機能遂行上、非常に高い優先度で処理されるべきです。システムの設計において、JWT検証コンポーネントが十分なリソース(CPU、メモリ)と優先度を持つように考慮する必要があります。
まとめ
RFC 7519によって定義されるJWTは、ステートレスな認証・認可の要件を満たす強力なメカニズムです。そのコンパクトさ、自己完結性、安全性、相互運用性から、現代の分散システムやウェブアプリケーションにおいて広く採用されています。しかし、その実装と運用には、リプレイ攻撃、アルゴリズムダウングレード、鍵管理、0-RTTのセキュリティリスクといった固有の注意点が存在します。
ネットワークエンジニアとしては、JWTのサイズがネットワークパフォーマンスに与える影響(MTU、ヘッダ圧縮)、そしてJWT検証の遅延がアプリケーションのスループットに与える影響を理解し、適切な設計と最適化を行うことが重要です。セキュリティとパフォーマンスの両面から、JWTの特性を深く理解し、堅牢なシステム構築に貢献していく必要があります。

