コンテンツにスキップ

セキュリティに関する考慮事項

トークン検証が重要な理由

リソースサーバーの主要なセキュリティ責任は、すべての受信リクエストが信頼できる認可サーバーによって発行された有効で改ざんされていないアクセストークンを持っていることを確認することです。トークン検証の失敗は以下につながる可能性があります:

  • 不正アクセス — 有効な資格情報なしに攻撃者が保護されたリソースにアクセスする
  • 権限昇格 — 偽造されたスコープを持つトークンが昇格された権限を付与する
  • トークンリプレイ — 盗まれたトークンが異なるコンテキストから再利用される
  • データ流出 — 侵害されたトークンを使用して機密データが抽出される

@authrim/serverは多層防御の原則に基づいて設計されています。すべての検証ステップは、既知の攻撃ベクトルに対して耐性を持つように実装されています。

組み込みセキュリティ機能

SDKにはデフォルトで以下のセキュリティ対策が含まれています。これらの保護は常にアクティブであり、誤って無効にすることはできません。

1. タイミングセーフ比較

セキュリティ上重要なすべての文字列比較は、タイミングサイドチャネル攻撃を防止するために定時間アルゴリズムを使用します:

  • 発行者(iss)の検証 — 攻撃者がどの発行者が信頼されているかを探ることを防止
  • オーディエンス(aud)の検証 — 受け入れられるオーディエンス値の探索を防止
  • DPoP Thumbprintバインディング — 期待されるThumbprint値の推測を防止

タイミングセーフ比較により、2つの文字列を比較するのにかかる時間が一致する文字数を明らかにしないことが保証され、情報漏洩が排除されます。

2. alg: noneの拒否

SDKは、ヘッダーにalg: noneを持つJWTを拒否し、InsecureAlgorithmErrorをスローします。「none」アルゴリズムはトークンが未署名であることを意味し、これを受け入れると誰でもトークンを偽造できてしまいます。

// The SDK automatically rejects this — no configuration needed
// Header: { "alg": "none", "typ": "JWT" }
// Result: InsecureAlgorithmError

この保護は無効にできません。未署名トークンを許可する設定オプションはありません。

3. HTTPSの強制

デフォルトでは、requireHttps: trueによりすべての外部URLがHTTPSを使用することが保証されます:

  • 発行者URL
  • JWKSエンドポイント
  • イントロスペクションエンドポイント
  • 失効エンドポイント

HTTP URLは、ネットワークリクエストが行われる前の設定時に拒否されます。

4. SSRF対策(JWKSリダイレクトブロック)

JWKSを取得する際、SDKはクロスオリジンリダイレクトをブロックします。これにより、悪意のある認可サーバーがJWKSフェッチを内部ネットワークリソースにリダイレクトするServer-Side Request Forgery(SSRF)攻撃を防止します。

JWKSエンドポイントが異なるオリジンへのリダイレクトを返した場合、SDKはリダイレクトに従う代わりにエラーをスローします。

5. JWTサイズ制限(8 KB)

SDKはサービス拒否攻撃を防止するために8 KBを超えるJWTを拒否します。過大なトークンは以下に使用される可能性があります:

  • Base64デコード時のメモリ枯渇
  • 署名検証時の過度なCPU使用
  • リクエスト処理の遅延

正当なアクセストークンは通常2 KB未満です。

6. シングルフライトJWKSフェッチ

複数のリクエストが同時に到着してJWKSリフレッシュをトリガーした場合、SDKはそれらを単一のネットワークリクエストに統合します。この「シングルフライト」または「サンダリングハード」防止により:

  • 認可サーバーへの並列JWKSリクエストの過負荷を回避
  • 同時検証間で一貫した鍵の状態を確保
  • 待機中のすべてのリクエストのレイテンシを削減

7. 公開鍵のみのJWKインポート

DPoPプルーフを処理する際、SDKはプルーフヘッダーのJWKから公開鍵パラメータのみをインポートします。秘密鍵パラメータ(dpqdpdqqi)は拒否されます。

これにより以下を防止します:

  • 攻撃者がプルーフに秘密鍵を埋め込んでサーバーを騙すこと
  • ログやエラーメッセージを通じた偶発的な秘密鍵の漏洩

8. exp / nbf / iatのクロック許容値

clockToleranceSeconds設定(デフォルト: 60秒)は、認可サーバーとリソースサーバー間のクロックスキューに対するバッファを提供します。SDKはこの許容値を以下に適用します:

  • exp(有効期限) — 有効期限からclockToleranceSeconds経過するまでのトークンを受け入れ
  • nbf(有効開始時刻) — 有効開始時刻のclockToleranceSeconds前までのトークンを受け入れ
  • iat(発行時刻) — clockToleranceSeconds以上未来に発行されたトークンを拒否

9. リクエストボディ消費の保護

フレームワークミドルウェアアダプタは、アプリケーションがボディを読み取る前にボディを消費してしまうことを避けるため、リクエストボディの解析を慎重に処理します。Authorizationヘッダーからのトークン抽出はヘッダーのみを対象としており、ボディ処理に干渉しません。

10. DPoPにおける秘密鍵漏洩の防止

SDKはDPoP検証に秘密鍵を要求も処理もしません。リソースサーバーは、プルーフの署名を検証してJWK Thumbprintを計算するために、DPoPプルーフヘッダーの公開鍵のみを必要とします。

やってはいけないことチェックリスト

クライアント設計ガイダンス

コンフィデンシャルクライアントを作成すべき場合

@authrim/serverの一部の機能にはclientCredentials(クライアントIDとシークレット)が必要です。コンフィデンシャルクライアントが必要になるのは以下の場合です:

機能clientCredentialsが必要理由
トークン検証(JWT)いいえ公開鍵を使用してローカルで検証
DPoP検証いいえプルーフの署名を使用してローカルで検証
トークンイントロスペクションはい認可サーバーが呼び出し元を認証する
トークン失効はい認可サーバーが呼び出し元を認証する

JWTアクセストークンの検証のみを行う場合、クライアント資格情報は不要です。イントロスペクションまたは失効が必要な場合にのみ、コンフィデンシャルクライアントを登録してください。

// For JWT validation only — no credentials needed
const authrim = new AuthrimServer({
issuer: 'https://auth.example.com',
audience: 'https://api.example.com',
});
// For introspection/revocation — credentials required
const authrim = new AuthrimServer({
issuer: 'https://auth.example.com',
audience: 'https://api.example.com',
introspectionEndpoint: 'https://auth.example.com/oauth/introspect',
revocationEndpoint: 'https://auth.example.com/oauth/revoke',
clientCredentials: {
clientId: 'my-resource-server',
clientSecret: 'resource-server-secret',
},
});

オーディエンスとスコープの設計パターン

オーディエンスとスコープの値は慎重に設計してください:

  • APIごとに1つのオーディエンス — 各APIサービスに一意のオーディエンスURIを使用します(例: https://api.example.comhttps://billing.example.com
  • スコープの粒度 — 広いread / writeではなく、read:userswrite:ordersadmin:settingsのようなスコープを使用します
  • 最小権限 — クライアントアプリケーションは必要なスコープのみをリクエストすべきです

トークンの有効期間に関する推奨事項

アプリケーションの責任

SDKはほとんどのセキュリティ上の懸念を自動的に処理しますが、一部の責任はアプリケーション側に残ります。

DPoP jtiリプレイ保護

SDKはDPoPプルーフの構造、署名、バインディングを検証しますが、リプレイ検出のためのjti値の追跡は行いません。これは、リプレイ保護にはサーバーサイドの状態(最近見たjti値のキャッシュ)が必要であり、デプロイメントによって異なるためです。

バックチャネルログアウトのjti検証

同様に、BackChannelLogoutValidatorはログアウトトークンの構造とクレームを検証しますが、jti値の追跡は行いません。アプリケーションでは以下を行う必要があります:

  1. JWT署名を検証する(バリデータが解析済みトークンを提供します)
  2. jtiが以前に使用されていないことを確認する
  3. 対応するユーザーセッションを無効化する

エラーレスポンスのフォーマット

SDKは型付きエラー(例: TokenExpiredErrorInvalidSignatureError)をスローしますが、HTTPエラーレスポンスのフォーマットは行いません。アプリケーションまたはミドルウェアアダプタがこれを処理します:

// Example: Express error handler
app.use((err, req, res, next) => {
if (err.name === 'TokenExpiredError') {
return res.status(401).json({ error: 'token_expired' });
}
if (err.name === 'InsufficientScopeError') {
return res.status(403).json({ error: 'insufficient_scope' });
}
next(err);
});

本番チェックリスト

本番環境にデプロイする前に、以下を確認してください。

インフラストラクチャ

  • HTTPSが有効 — すべてのエンドポイント(API、発行者、JWKS)がHTTPSを使用。requireHttpstrue(デフォルト)。
  • クロック同期 — サーバーがNTPを使用してクロックを同期。clockToleranceSecondsを超えるクロックドリフトは誤ったトークン拒否を引き起こします。
  • DNS解決 — 発行者のホスト名が正しく解決され、DNSスプーフィングに脆弱でないこと。

設定

  • 発行者URLが正しい — トークンのissクレームと正確に一致(末尾スラッシュの動作を含む)。
  • オーディエンス値が正しい — トークンのaudクレームと一致。
  • クロック許容値が妥当 — デフォルト60秒。300秒を超えないこと。
  • JWKSキャッシュTTLが適切 — デフォルト1時間(jwksRefreshIntervalMs: 3600000)。鍵ローテーションの頻度に基づいて調整。

アプリケーションコード

  • トークンがログに記録されていない — 生のトークン文字列の代わりにsubjtiscopeiatをログに記録。
  • エラーレスポンスが内部詳細を漏洩していない — クライアントには汎用的なエラーコードを返し、詳細はサーバーサイドでログに記録。
  • エンドポイントごとにスコープが適用されている — すべての保護されたエンドポイントが必要なスコープを指定。
  • DPoP jtiリプレイ保護が実装されている — DPoPを使用する場合、キャッシュ(例: Redis)でjti値を追跡。
  • バックチャネルログアウトが処理されている — バックチャネルログアウトを使用する場合、jtiの追跡とセッション無効化を実装。

鍵ローテーション

  • 鍵ローテーション戦略が定義されている — 認可サーバーが署名鍵を定期的にローテーション。
  • JWKSキャッシュがローテーションに対応 — SDKはkidが見つからない場合に自動的に再試行しますが、環境で動作することを確認。
  • 古い鍵が削除されている — 猶予期間後、侵害された鍵の使用を防止するために古い鍵をJWKSから削除。

モニタリング

  • トークン検証の失敗がログに記録されている — 攻撃を示す可能性のあるスパイクを監視。
  • JWKSフェッチの失敗がアラートされている — SDKが鍵を取得できない場合、すべてのトークン検証が失敗します。
  • クロックドリフトが監視されている — NTP同期が失敗した場合にアラート。

脅威モデルの概要

以下の表は、一般的な攻撃とSDKの組み込み防御のマッピングを示しています:

脅威攻撃ベクトルSDKの防御
トークン偽造alg: noneを使用した偽造JWTInsecureAlgorithmErroralg: noneを拒否
トークン偽造不正な鍵で署名されたJWTJWKS kidマッチングによる署名検証
トークンリプレイ盗まれたBearerトークンDPoP送信者制約(アプリケーションレベルのjti追跡)
タイミング攻撃発行者/オーディエンス値の探索タイミングセーフ文字列比較
SSRF悪意のあるJWKSリダイレクトクロスオリジンリダイレクトブロック
DoS過大なJWTペイロード8 KBサイズ制限
サンダリングハード同時JWKSリフェッチシングルフライトパターン
鍵の混乱DPoPプルーフ内の秘密鍵公開鍵のみのインポート
期限切れトークンクロックスキューの悪用上限付きの設定可能なクロック許容値
中間者攻撃HTTP経由のトークン傍受HTTPSの強制(設定可能)
権限昇格スコープチェックの欠如各エンドポイントでのrequiredScopes検証

この脅威モデルを理解することで、特定のデプロイメントに追加のアプリケーションレベルのセキュリティ対策が必要かどうかを評価できます。

次のステップ