JWT:構造と脆弱性
1) JWTとは何ですか、どこで使用されていますか
JWTは'Base64Url(ヘッダー)形式のコンパクトな自己完結型クレーム・コンテナです。Base64Url(ペイロード)。Base64Url(署名)'。
のために使用される:- JWS(署名されたトークン-信頼性/整合性)、
- JWE(暗号化されたトークン-プライバシー)、
- アクセス/IDトークンとサービス間の認証としてOIDC/OAuth2します。
長所:自律性、キャッシュ性、低いオーバーヘッド。短所:誤った検証、複雑なリコールケースのリスク。
2) JWT構造
2.1ヘッダー(JSON)
最小:アルゴリズムとキー識別子。
json
{ "alg": "ES256", "kid": "jwt-2025-10", "typ": "JWT" }
'alg':署名/暗号化アルゴリズム(RS256/ES256/PS256/HS256など)。
'kid':キーへのポインタ(JWKS回転用)。
オプションのキー・ソース: 'jku'、 'x5u'(脆弱性第6条を参照。3).
2.2ペイロード(JSON)
標準化されたスタンプ:- 'iss'(発行者)、'aud'(聴衆)、'sub'(件名)
- 'exp'(有効期限)、'nbf'(以前ではない)、'iat'(発行された)
- 'jti' (トークンID、取り消し可能)
- domain-stamps: 'scope/roles'、 'tenant'、 'kyc_level'など。
2.3つの署名
JWS='sign (base64url (header)+「。」+base64url (payload)、 private_key)'
検証:厳密に対応する公開鍵と、サーバーが期待する正確なアルゴリズム。
3)基本的なチェック不変量
1.アルゴリズムはリソースサーバー(allow-list)の設定によって固定され、'header'の内容では信頼されません。alg'。
2.'iss'と'aud'の正確なマッチをチェックします。'exp/nbf'-小さな'clock_skew' (± 30-60)を考慮してください。
3.「キッド」なしでトークンを拒否するのは、1つのキーとローテーションがない場合のみです。そうでなければ「子供」を要求します'.
4.オブジェクトレベル認証(BOLA-first)なしでスタンプを信頼しないでください。
5.解析-暗号検証後;デコードする前の基本的なサイズの点検。
4) JWS vs JWE
JWS:署名されているが読みやすい。ペイロードPII/シークレットを入れないでください。
JWE:ペイロードを暗号化します。統合はより困難であり、キーモデルは重要です。
ほとんどのAPIでは、ペイロード内の機密データに対するJWS+の禁止は十分です。
5)トークンのライフサイクル
アクセス:短期(5-30分)。
リフレッシュ:より長い(7-30日)、使用中に回転(1回)、「ブラックリスト」'jti/sid'を保持します。
失効:TTLの'jti'、不透明なトークンの内省、インシデントの'exp'の略語をリストします。
キー回転:オーバーラップ付きJWKS(古い+新しい)、記事「キー回転」を参照してください。
6)頻繁な脆弱性とそれらを閉じる方法
6.1 'alg=none'/アルゴリズム置換
ボトムライン:サーバーは'alg'フィールドを信頼し、符号なしトークンを受け取ります。
保護:サーバー上のアルゴリズムのhard allow-list;'none'と予期しない値を拒否します。
6.2 RS256→HS256スワップ(対称化)
ボトムライン:攻撃者はHS256で「alg」を置き換え、公開鍵をHMACシークレットとして使用します。
保護:構成のアルゴリズムにキーを結合して下さい;1つの'kid'に対称/非対称プロバイダを混在させないでください。
6.3キーインジェクション('kid/jku/x5u')
シナリオ:- 'jku'は攻撃者が制御するJWKSを指します(キーをスリップします)。
- 'x5u'/'x5c'外部証明書の乱用。
- /SQLパスインジェクション('。。"/。。/privkey。pem"'または''OR 1=1--')。
- 削除された'jku/x5u'を無視するか、厳密なallistドメインでフィルターします。
- 'kid'はローカルディレクトリ(table/cache)のキーとしてのみ使用され、ファイルパス/SQLの連結は使用されません。
- 信頼されたURL、短いTTL、署名/ピンチャネルからJWKSをロードします。
6.4 HS256の弱い秘密(ブルートフォース)
ボトムライン:HMACシークレットはショート/リーク→シグネチャースプーフィングです。
保護:非対称性(RS/ES/PS)または秘密長≥ 256ビット、秘密-KMSでのみ使用します。
6.5スタンプが見つからない/無効な
'aud'/' iss'/'exp'→トークンはクロスサービス可能または無限です。
長すぎる'経験'→妥協のリスク。
保護:マークのフルセット、'exp' short、 'nbf'/'iat'を'clock_skew'で検証する必要があります。
6.6リプレイとトークン盗難
本質:トークンの傍受/反復(ログ、XSS、 TLSなしのMitMでのリーク)。
保護:- TLS 「Secure」+「HttpOnly」 Cookie、 SameSite=Lax/Strict。
- パートナーのためのDPoP/PoP(クライアントキーにトークンをバインドする)および/またはmTLS。
- 短い'経験'、リフレッシュ回転、デバイスバインディング。
6.7 XSS/ストレージリーク
ボトムライン:'localStorage'/'sessionStorage'のJWTストレージは→JSで利用可能です。
保護:HttpOnly-Cookie (Cookieモデルが可能な場合)+厳密なCSP/Trusted Typesにアクセストークンを保存します。
クッキーなしのSPAの場合-メモリ内のトークンを隔離し、最小限に生き、XSSから保護します。
6.8 CSRF
ボトムライン:Cookieセッション中、サードパーティのサイトからのリクエスト。
保護:SameSite、 アンチCSRFトークン(二重送信)、'Origin/Referer'チェック、Fetch-Metadataフィルタ。
6.9サイズ超過/サイズ乱用
Gist:巨大なペイロード/見出し、解析のDoS。
保護:タイトル/ボディサイズ制限、早期拒否431/413、スタンプの固定セット。
6.10置換'typ'/'cty'
本質:型の混乱('typ:' JWT')、入れ子のJOSEオブジェクト。
保護:セキュリティのために'typ/cty'を無視し、固定アルゴリズムとブランディングスキームに依存します。
7)トークンの保管と転送
7.1サーバAPI(マシン間)
mTLS/HMAC、できればJWTの非対称性、メッシュを介したチャネル。
キーストア-KMS/HSM、スケジュールされた回転、JWKSの重複。
7.2ブラウザクライアント
HttpOnly Secure Cookieへのアクセス/更新;短いTTL;update-HTTPSの下で「SameSite=None」で「silent refresh」を経由します。
厳密なCSPの信頼されたタイプはXSSから、保護します;SPAの場合-可能であれば、トークンをディスクに保存しないでください。
8) JWKS、回転およびリコール
JWKSは、認可者によって発行されます。消費者は5〜15分間キャッシュします。
回転計画:新しい'kid'を追加する→署名を開始する→N日後にJWKSから古いものを削除する→purge。
フィードバック:'jti/sid'リストとTTL;インシデントが発生した場合は、一時的に'exp'とforce-logout(リフレッシュを無効にする)を削減します。
9)マルチテナントとデータの最小化
アーキテクチャによって必要な場合にのみ'tenant'/'org'をトークンに含める。それ以外の場合は、PDPから'sub'で属性を取得します。
PIIはありません。切手の最低セット→漏出および相関のより少ない危険。
10)実用的な検証チェックリスト(リソースサーバー)
- 署名と基本サイズ制限の検証後にのみParsim。
- 設定から'alg';予期しないものを拒否します。
- 'iss' ∧ 'aud' ∧ 'exp' ∧ 'nbf' ∧ 'iat' ('clock_skew')をチェックします。
- ローカルディレクトリ/JWKS(短いTTL)で'kid'をチェックします。
- 外部ポインタをフィルタ/正規化する('jku/x5u'-allow-listのみ)。
- スタンプの長さ/構成(スキーム)を制限します。
- Object Resource Authorization (BOLA-first)を適用します。
- ログイン'kid'、 'sub'、 'aud'、 'iss'、 'jti'、 'exp'、 'tenant'、 'trace_id' (PIIなし)。
- 署名エラー、遅延、回転監査の指標。
11)セキュアポリシーの例(擬似)
11.1アルゴリズム期待値の設定
yaml jwt:
expected_issuer: "https://auth. example. com"
expected_audience: ["wallet-service"]
allowed_algs: ["ES256"] # fix the jwks_url: "https ://auth. example. com/.well-known/jwks. json"
jwks_cache_ttl: 600s clock_skew: 60s required_claims: ["iss","aud","sub","exp","iat"]
11.2リモート'jku/x5u'をドロップ'
yaml reject_untrusted_key_sources: true allowed_jku_hosts: ["auth. example. com"] # if absolutely necessary
11.3サンプルフィードバックリスト(Redis)
pseudo if redis. exists("revoke:jti:" + jti) then deny()
if now() > exp then deny()
12)観測可能性と発生率
'jwt_verify_fail_total {reason}'、 'jwt_expired_total'、 'jwks_refresh_total'、 'kid'。
ログ(構造化):'iss/aud/sub/kid/jti/exp/tenant/trace_id'、失敗の理由。
ダッシュボード:「期限切れ」、検証エラーの急増、地域/クライアント別の配布。
アラート:'verify_fail'(署名/アルゴリズム)の増加、JWKSエラー、有効期限切れのトークンの共有。
13) Antipatterns
トークンから'alg'を信頼する。'none'をサポートします。
長寿命のアクセストークンとリフレッシュローテーションはありません。
KMSなしでENVの短い秘密/秘密を持つHS256。
任意のドメインから'jku/x5u'を受け入れる。allow-listなしでJWKSを動的にロードします。
ペイロードJWSにPII/secretsを入れます。
XSSリスクが存在する場合は、トークンを'localStorage'に保存します。
検証エラーを抑制します(200秒「ソフトエラー」を返します)。
BOLAは'scope/role'のみにチェックして依存しません。
14) iGaming/Financeの詳細
ブランド:'kyc_level'、 'risk_tier'、 'tenant'、 strict 'aud'。
書き込み操作用の短いTTL (deposits/outputs)、重要なルート用のPoP/DPoPまたはmTLS。
規制監査:入力/障害の変更不可のログ、地域の境界内のログの保存。
パートナー/PSPには、個別のキー/'aud'、テナントキー、および個別のJWKSがあります。
15) Prod Readinessチェックリスト
- アルゴリズムのハード許可リスト;'none'は許可されません。
- 'iss/aud/exp/nbf/iat/jti'がチェックされます。短い'exp'。
- オーバーラップされたJWKS、短いTTLキャッシュ;「キッド」シェアの監視。
- リフレッシュ-rotate-on-use;'jti/sid'リストとTTL;Playbookのレビュー。
- 重要なルート上のPoP/DPoPまたはmTLS。
- ブラウザのHttpOnly-Cookie、 CSP/Trusted Types vs。 XSS;CSRF保護。
- ペイロードにPIIはありません。マークの最小セット。
- 検証と失敗のメトリック/ログ;アラートをJWKS/verify_failします。
- ネガティブシナリオテスト:RS→HSスワップ、'kid'-インジェクション、'jku'スプーフィング、オーバーサイズ、クロックスキュー。
16) TL;DRについて
サーバー側のアルゴリズムとキーを修正し、トークンから'alg'を信頼しないでください。'iss/aud/exp/nbf/iat/jti'を要求します。JWKSの重複を介してキーを回転させ、トークンを短命に保ち、使い捨てに更新します。トークンを安全に保存(Web用のHttpOnly-Cookie)、スタンプを最小限に抑え、PIIを入れないでください。'jku/x5u/kid'ベクトルを閉じ、弱い秘密のHS256を避け、クリティカルパスにPoP/DPoPまたはmTLSを追加し、常にリソースレベルでBOLAチェックを行います。