JWTの署名アルゴリズム:RS256 vs HS256、その「見えない境界線」を設計する
セキュリティアーキテクトであれば、JWT(JSON Web Token)の実装における「アルゴリズム選択」が、単なる暗号方式の選定ではなく、システム全体の信頼境界(Trust Boundary)の設計そのものであることを理解しているはずだ。
現場で散見されるのは、「HS256で十分」という短絡的な判断による鍵管理の崩壊だ。今日は、RS256とHS256の使い分けを、低レイヤの脆弱性トレンドと鍵管理の泥臭い現実という観点から解体していく。
—
1. 鍵管理の心理戦:HS256の「共有」という名の脆弱性
HS256(HMAC with SHA-256)は共通鍵暗号だ。署名生成と検証で「同一の秘密鍵」を共有する。このアーキテクチャが孕む最大の弱点は、検証側のサービスすべてが署名生成能力を持ってしまうという点にある。
例えば、認証認可を行うIDP(Identity Provider)と、それを利用する複数のマイクロサービスがあるとしよう。HS256を採用すれば、すべてのマイクロサービスに同じ秘密鍵を配布しなければならない。もし、一番防御の薄い末端のサービスがメモリダンプ攻撃や設定ミスで侵害されたらどうなるか? 鍵が漏洩した瞬間、システム全体の認証プロトコルが完全に崩壊する。
攻撃者の視点:
攻撃者は、JWTヘッダーを `{“alg”: “none”}` に書き換える攻撃(CVE-2015-9235的アプローチ)だけでなく、HS256の鍵を辞書攻撃で特定し、自分自身で偽のトークンを発行する(Impersonation)。秘密鍵が複数のサーバーに散らばっている環境は、攻撃者にとって「どこからでも侵入できる巨大な玄関」に等しい。
2. RS256:非対称鍵が実現する「最小権限の原則」
一方、RS256(RSA Signature with SHA-256)は公開鍵暗号だ。IDPは秘密鍵で署名を行い、検証側は公開鍵で検証する。ここには明確な非対称性がある。
- 検証側: 公開鍵しか持たない。たとえ検証側のサーバーが侵害されても、トークンの偽造は不可能だ。
- 署名側: 秘密鍵はIDPのメモリ空間(またはHSM/KMS内)に隠蔽される。
大規模な分散システムにおいて、セキュリティの責任境界線を明確に引くにはRS256一択だ。鍵管理コストが高いと嘆くテックリードがいるが、それはKMS(AWS KMSやHashiCorp Vault)を活用すれば解決する問題だ。鍵のローテーション戦略も、公開鍵のみを配信するRS256の方が、全サービスを一斉に止める必要がない分、遥かに運用に耐えうる。
実装におけるベストプラクティス(RS256推奨設定)
// Node.js (jsonwebtoken) を使用した安全な検証処理の例
const jwt = require(‘jsonwebtoken’);
const fs = require(‘fs’);
// 公開鍵を読み込む(IDPから定期的にJWKSエンドポイント経由で取得しキャッシュするのが理想)
const publicKey = fs.readFileSync(‘public_key.pem’, ‘utf8’);
try {
// 検証時にアルゴリズムを明示的に固定する
// alg: ‘none’ や HS256への強制切り替え攻撃を防ぐための必須設定
const decoded = jwt.verify(token, publicKey, { algorithms: [‘RS256’] });
// 認可ロジックへ
console.log(‘検証成功: トークンは信頼できる署名によって保証されています’);
} catch (err) {
// ログには詳細を出しすぎず、攻撃の痕跡(不正なトークンの試行)として監視に飛ばす
console.error(‘トークン検証エラー: 不正な署名または改ざんの試行’);
}
3. 次世代を見据えた暗号アルゴリズムの選定
現在、我々は耐量子計算機暗号(PQC)への移行期に片足を突っ込んでいる。RS256で使われるRSAアルゴリズムは、ショアのアルゴリズムによって将来的に解読されるリスクがある。
今後、JWTの実装において考慮すべきは、「暗号の機敏性(Crypto Agility)」だ。コードベースでアルゴリズムをハードコードするのではなく、プロバイダーが提供する公開鍵セット(JWKS)のメタデータを動的に取得し、サポートするアルゴリズムを常に最新の暗号強度に合わせて更新できる設計にしておく必要がある。
また、生成AIを活用したアプリケーションにおいては、プロンプトインジェクションによってJWTのペイロードやヘッダーが操作されるリスクも想定しなければならない。トークンを検証する層は、アプリケーションロジックとは完全に分離された「ガードレイル」として動作させるべきだ。
結論:技術的負債を「セキュリティの境界線」で解決する
- HS256を使っていいのは、 閉じた環境で、鍵の管理が一元化されており、かつ認証サービスと検証サービスが物理的に同じ信頼領域にある場合だけだ。
- RS256を使うべきなのは、 それ以外、つまり現代のほとんどすべてのマイクロサービスアーキテクチャだ。
「鍵管理が面倒だからHS256」という選択は、セキュリティをコストと履き違えたエンジニアの怠慢に過ぎない。公開鍵を配布するコストを払うか、秘密鍵を漏洩させるリスクを背負うか。この二択を突きつけられた時、迷わず前進できるのが、真のセキュリティアーキテクトだ。
次にJWTを触る時は、ヘッダーに埋め込まれた `alg` をただの文字列として見るのではなく、その向こう側に広がる信頼の連鎖を想像してみてほしい。それが、脆弱性を未然に防ぐ唯一の道だ。

コメント