ASP.NET Core で UUIDv7 のタイムスタンプ部を UUIDv47 アルゴリズムでマスクし、可逆的に変換するライブラリです。
このライブラリは UUIDv47Sharp (C#実装)を使用して、GUID を可逆的にマスク化します。
UUIDv47 は UUIDv7 のタイムスタンプ部を隠蔽するための可逆エンコーディング形式です。
- UUIDv7 → UUIDv47: 128bit キーで XOR 暗号化し、タイムスタンプを隠蔽
- 可逆性: 同じキーを使用すれば、UUIDv47 から元の UUIDv7 を復元可能
- キー管理:
IMaskedUUIDKeyProviderでキーを提供(テナントごとに異なるキーなど柔軟に対応可能)
- uuidv47 - Go実装(オリジナル)
- UUIDv47Sharp - C#実装
UUIDv7 は先頭48ビットにタイムスタンプを含むため、そのまま公開すると リソースの作成日時が暴露 されてしまいます。
これにより以下のような情報漏洩リスクがあります:
- ユーザー登録日時、注文日時などの 業務情報が推測可能
- 新規ユーザー数や 成長率が外部に漏洩
- 競合他社に ビジネス状況を把握される
このライブラリは、以下のタイミングで自動的に UUIDv7 ↔ UUIDv47 変換を行います:
- API レスポンス:
MaskedGuid型のプロパティが JSON に出力される際、UUIDv47 に変換 - API リクエスト: UUIDv47 文字列を受信時、自動的に元の GUID に復元
- URL パラメータ:
/items/{id}のような URL で UUIDv47 の ID を受け取り、自動復元 - SignalR: Hub の送受信で
MaskedGuid型のプロパティを自動変換
MaskedGuidは JSON の入出力のみ でマスク(エンコード/デコード)されます。MaskedGuid.ToString()は 生のGuid文字列 を返します(マスク文字列ではありません)。
MaskedGuidは JSON 変換時にIMaskedUUIDServiceを使ってマスク化します。Guid.Empty(空 GUID) は JSON 出力でnullになります。- JSON 入力の
null/""(空文字)はGuid.Emptyとして扱われます。
MaskedGuid用の JSON 変換はHttpContextからIMaskedUUIDServiceを解決します。- そのため HTTP リクエスト外(バックグラウンド処理や非 Web 環境)で
MaskedGuidを JSON シリアライズ/デシリアライズすると例外になります。
- URL/クエリのバインドは
MaskedGuid/MaskedGuid?型のみ 対象です。 [MaskedUUID]属性は使用しません(属性ベースの処理はありません)。MaskedGuid?はデコード結果がGuid.Emptyの場合nullとして扱われます。MaskedGuidはデコード結果がGuid.Emptyの場合Guid.Emptyのまま扱われます。- JSON 変換でも
Guid.Emptyはnullとして出力され、読み込み時はGuid.Emptyとして扱われます。
- JSON 変換でも
IMaskedUUIDKeyProviderを登録IMaskedUUIDServiceを登録AddMaskedUUID()とAddMaskedUUIDModelBinder()を追加
サンプルは samples/MaskedUUID.Sample を参照してください。
// KeyProviderを登録(Singleton推奨、Scopedも可)
builder.Services.AddSingleton<IMaskedUUIDKeyProvider, MyKeyProvider>();
// MaskedUUID対応を追加
builder.Services.AddMaskedUUID();
// ModelBinderを追加(URL/クエリパラメータ用)
mvcBuilder.AddMaskedUUIDModelBinder();
// または一括で
mvcBuilder.AddMaskedUUIDControllers();SignalR対応には AddMaskedUUID() 拡張メソッドを使用します。
// KeyProviderを登録
builder.Services.AddSingleton<IMaskedUUIDKeyProvider, MyKeyProvider>();
// SignalRにMaskedUUID対応を追加
builder.Services.AddSignalR().AddMaskedUUID();SignalR用のコンバーターは以下の優先順位でサービスを解決します:
- Hubスコープ - Hub呼び出し内のスコープ(HubFilter経由)
- HttpContextスコープ - HTTP接続の場合
- 一時スコープ - フォールバック
これにより、KeyProvider/Serviceが Singleton / Scoped / Transient のいずれでも正しく動作します。
// 開発/テスト用に参照キーを使用(本番では使用しないでください)
builder.Services.AddSignalR().AddMaskedUUIDWithReferenceKeys();.NET 10以降 / .NET 9 に対応しています。
// OpenAPIスキーマトランスフォーマーを追加
builder.Services.AddOpenApi(options => options.AddMaskedGuidSchemaTransformer());.NET 10以降では JsonSchemaType enum、.NET 9では文字列ベースの型指定に自動的に対応します。