.NET Data Protection と認証クッキーのセキュリティ
ASP.NET Core のデータ保護 (Data Protection) スタックは、認証クッキーや CSRF トークンなどの機密データを暗号化・改ざん防止するために不可欠なコンポーネントです。本ドキュメントでは、認証クッキーにおける Data Protection Key の役割、その管理方法、および認証サーバーの情報漏洩時における緊急対応策について解説します。
Data Protection API (DPAPI) の概要
ASP.NET Core の Data Protection API は、アプリケーションがデータを暗号化および復号化するためのシンプルな API を提供します。
認証クッキーでの役割
ASP.NET Core Identity や Cookie 認証ミドルウェアは、ユーザーの ID やクレームを含む認証チケットを作成し、それを暗号化してクッキーに保存します。この暗号化に使用されるのが Data Protection Key (キーリング) です。
- 認証チケットの作成: ユーザー情報 (ClaimsPrincipal) から認証チケットを作成。
- シリアへと保護: チケットをシリアライズし、Data Protection Provider を使用して暗号化・署名。
- クッキーの発行: 保護されたペイロードを
.AspNetCore.Cookiesなどのクッキーとしてクライアントに送信。
クライアントからクッキーが送り返されると、サーバーは同じキーリングを使用してクッキーを復号し、改ざんされていないことを検証します。
.NET での Data Protection の扱い方
デフォルトでは、ASP.NET Core はキーをローカルファイルシステムや環境変数に基づいて自動的に管理しますが、本番環境 (特に複数インスタンス構成) では明示的な設定が必要です。
基本的な設定 (Program.cs)
using Microsoft.AspNetCore.DataProtection;
var builder = WebApplication.CreateBuilder(args);
// Data Protection の設定
builder.Services.AddDataProtection()
// キーの保存場所 (Azure Blob Storage など)
.PersistKeysToAzureBlobStorage(new Uri("https://<storage-account>.blob.core.windows.net/keys/keys.xml"), new DefaultAzureCredential())
// キーの暗号化 (Azure Key Vault など)
.ProtectKeysWithAzureKeyVault(new Uri("https://<key-vault>.vault.azure.net/keys/dataprotection"), new DefaultAzureCredential())
// アプリケーション識別子 (同じアプリの別インスタンス間でキーを共有するため)
.SetApplicationName("MyApplication");
var app = builder.Build();
キーの永続化と共有
ロードバランサー背下の複数サーバー構成 (Web Farm) やコンテナ環境 (Kubernetes) では、すべてのインスタンスが同じキーリングを共有する必要があります。
- キーの保存場所: ローカルディスクではなく、共有ストレージ (Azure Blob Storage, AWS S3, Redis, SQL Server) に保存します。
- 保存時の暗号化: キー自体も暗号化して保存することが推奨されます (Azure Key Vault, X.509証明書など)。
もし各サーバーが異なるキーを持っていると、サーバーAでログインしたユーザーのクッキーをサーバーBが復号できず、ログイン状態が維持されません。
OpenID Connect (OIDC) 認証サーバー漏洩時の対応
OAuth 2.0 / OpenID Connect 準拠の認証サーバー (IdP) のユーザー情報が外部に漏洩した場合、または署名鍵が侵害された場合、Relying Party (RP) である Web アプリケーション側でも迅速な対応が必要です。
想定されるリスク
- トークンの偽造: 署名鍵が漏洩すると、攻撃者が任意のユーザーになりすました ID トークンやアクセストークンを発行できる可能性があります。
- 既存セッションのハイジャック: 有効な認証クッキーやリフレッシュトークンが悪用される可能性があります。
対応策フロー
-
認証サーバー側での対応 (IdP)
- 侵害された署名鍵のローテーション (無効化と新規発行)。
- 既知の漏洩アカウントのパスワードリセットとセッション無効化。
-
Web アプリケーション側での対応 (RP)
- OIDC 設定の更新: IdP のメタデータエンドポイント (
.well-known/openid-configuration) から最新の公開鍵を取得し直す (通常は自動で行われますが、キャッシュ期間に注意)。 - 全ユーザーの強制ログアウト: 現在有効なすべての認証クッキーを無効化します。
- OIDC 設定の更新: IdP のメタデータエンドポイント (
Data Protection Key の無効化による強制ログアウト
最も確実かつ強力な強制ログアウト手段の一つは、現在の Data Protection Key を無効化 (Revoke) することです。これにより、以前のキーで暗号化されたすべての認証クッキーが復号できなくなり、全ユーザーが即座に未認証状態になります。
キーの無効化方法
ASP.NET Core の IDataProtectionProvider は、キーの管理を IXmlRepository を通じて行います。特定のキーを無効化する直接的な API は標準では露出していませんが、運用としては以下の方法があります。
1. キーファイルの削除/退避 (ファイルシステム・Blob の場合)
キーが保存されているストレージ上の XML ファイルを削除または移動させ、アプリケーションを再起動します。
- 影響: 過去に発行されたすべての保護データ (認証クッキー、CSRFトークンなど) が読み取れなくなります。
- 動作: アプリケーションは起動時に新しいキーを生成し、以降のログインは新しいキーで行われます。
2. アプリケーション名の変更
.SetApplicationName("MyApplication") の識別子を変更すると、論理的な分離が発生し、以前のアプリケーション名で保護されたデータを復号できなくなります。
// 変更前
// .SetApplicationName("MyApp_v1");
// 変更後
.SetApplicationName("MyApp_v2_Revoked20240301");
- メリット: コード変更とデプロイだけで完了する。
- デメリット: 永続化された他のデータ (もし DPAPI で暗号化してDBに保存している場合など) も読めなくなるため、影響範囲の精査が必要。認証クッキーのみを対象とする場合に有効です。
3. IKeyManager を使用したプログラムによる無効化 (高度)
Microsoft.AspNetCore.DataProtection.KeyManagement.IKeyManager インターフェースを使用すると、プログラムから特定のキーを Revoke することができますが、一般的な Web アプリ実装ではあまり行われません。
ベストプラクティス: 定期的なキーローテーション
緊急時だけでなく、通常運用でもキーのローテーションは自動的に行われます (デフォルトでは90日)。侵害対応計画の一部として、以下の手順をマニュアル化しておくことを推奨します。
- インシデント発生: IdP からの侵害通知を受領。
- 影響範囲特定: 影響を受けるのが認証セッションのみか、保存データも含むか確認。
- キー無効化の実行:
- Web Farm 全体の
ApplicationNameを変更して再デプロイ。 - または、共有ストレージ上のキーファイルをアーカイブし、アプリプールをリサイクル。
- Web Farm 全体の
- ユーザー通知: 全ユーザーに対し、セキュリティ上の理由で再ログインが必要である旨を通知。
まとめ
- Data Protection は ASP.NET Core のセキュリティの要であり、認証クッキーの安全性を担保しています。
- 外部 IdP 侵害時 は、IdP 側の対応だけでなく、RP 側でもセッションの無効化が必要です。
- キーの無効化 (ApplicationName の変更など) は、全ユーザーを強制的にログアウトさせるための強力なキルスイッチとして機能します。
- 本番環境では、キーの永続化 (Persistence) と暗号化 (Protection) を適切に構成し、インスタンス間での整合性を保つことが重要です。