adamy/RedactWire

GitHub: adamy/RedactWire

一款专为 .NET 设计的轻量级 PII 检测与脱敏库,支持基于校验和验证的跨国身份证件与敏感数据扫描。

Stars: 0 | Forks: 0

# RedactWire [![NuGet](https://img.shields.io/nuget/v/RedactWire.svg)](https://www.nuget.org/packages/RedactWire/) [![CI](https://github.com/adamy/RedactWire/actions/workflows/ci.yml/badge.svg)](https://github.com/adamy/RedactWire/actions/workflows/ci.yml) [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE) 一个用于 .NET 的轻量级、具备文化感知能力的 **PII 检测、验证和脱敏** 库。 RedactWire 以正则表达式为优先,并通过校验和进行验证:它不仅仅是匹配模式,还会 *验证*它们(信用卡使用 Luhn 算法,IBAN 使用 mod-97 算法,美国 SSN 使用地区/组别规则),因此 随机的 16 位数字不会被报告为信用卡。规则按文化进行分组, 结果会告诉你运行了哪些检查以及通过了哪些检查,并且每个匹配项都带有严重性级别, 用于驱动重叠项的解析。 - **目标框架:** `netstandard2.0` — 适用于 .NET Framework 4.6.1+、.NET Core、.NET 5–8+、 Mono、Unity、Xamarin。 - **依赖项:** 仅有一个,且只包含契约(`Microsoft.Extensions.DependencyInjection.Abstractions`), 因此 DI 引导程序开箱即用。没有其他运行时依赖。 - **许可证:** Apache 2.0。 ## 功能 - 不变(与国家/地区无关)规则:**Email**、**Credit card**(Luhn)、**IPv4**、 **IBAN**(mod-97)。 - **密钥检测** — API 密钥和 token(OpenAI、AWS、GitHub、Stripe、Slack、Google、 SendGrid、npm),**JWT** 和 **PEM 私钥**。通过 `AddSecretDetection()` 启用 (在静态 `Redactor` 中默认开启)。非常适合用于清洗 AI/LLM 日志。 - **内置 50+ 个国家/地区的规则包**(参见 [覆盖范围](#coverage)) — 国家 ID、税号、 电话号码、护照、邮政编码 — 大多数都受到真实校验位/算法的限制。 - **基于地区的解析:** 一个国家的语言共享一个规则包(`en-IN`/`hi-IN`/`ta-IN`, `en-CA`/`fr-CA`,`de-CH`/`fr-CH`/`it-CH`,新加坡的四种官方语言),而 不同国家的相同语言则保持独立(`zh-CN`/`zh-TW`/`zh-HK`/`zh-SG`)。 - **验证:** `Validate(value, [culture,] type)` → `Valid` / `Invalid` / `Unsupported`。 - **校验和控制:** 校验和失败的候选者将被丢弃 — 它不会被报告为 低置信度噪声。 - **严重性模型**(`Critical > High > Medium > Low`):用于重叠解析的主键 — 较高严重性的匹配项会覆盖重叠的较低严重性匹配项, 即使其置信度较低。 - **结构化扫描:** 检测 **JSON**、**XML** 和 **对象图** 中的 PII, 每个命中结果都通过 JSONPath / XPath / 属性路径进行定位。仅使用标准库 (`System.Text.Json`、`System.Xml`、反射);XML 解析是安全的(无 XXE)。 - **脱敏:** 掩码(保留长度)、移除、类型标签或自定义替换。 - **诚实的“无 PII”:** 如果请求的文化没有对应的规则包,会被标记为 `Supported = false`,而不是静默地“通过”。 - **可扩展:** 无需派生(fork)代码库即可按文化添加自定义规则(实现 `IPiiRule`, 或直接使用 `RegexRule`)。 ## 覆盖范围 不变(所有文化):**Email**、**Credit card**、**IPv4**、**IBAN**。 内置国家规则包(展示了代表性文化;一个国家的所有语言都会解析为 同一个规则包): | 地区 | 规则包 | |---|---| | 美洲 | `en-US` `en-CA` `es-MX` `pt-BR` `es-AR` `es-CL` `es-CO` | | 欧洲 | `en-GB` `fr-FR` `de-DE` `it-IT` `es-ES` `pt-PT` `nl-NL` `nl-BE` `de-CH` `de-AT` `pl-PL` `cs-CZ` `sk-SK` `hu-HU` `el-GR` `en-IE` `sv-SE` `nb-NO` `da-DK` `fi-FI` `is-IS` `et-EE` `lt-LT` `lv-LV` `sl-SI` `lb-LU` `ru-RU` `tr-TR` | | 亚太地区 | `zh-CN` `zh-HK` `zh-TW` `zh-MO` `ja-JP` `ko-KR` `en-IN` `id-ID` `vi-VN` `th-TH` `en-PH` `en-PK` `bn-BD` `en-SG` `ms-MY` `en-AU` `en-NZ` | | 中东 / 非洲 | `ar-SA` `ar-EG` `fa-IR` `he-IL` `en-NG` `en-ZA` | `PiiDetectorBuilder.AvailableCultures` 会在运行时返回此列表。每个规则包都有文档记录 在 [`docs/rules/localized/`](docs/rules/localized/) 下,验证状态记录在 [`docs/rules/VERIFICATION.md`](docs/rules/VERIFICATION.md) 中。 **标识符(可搜索,包括本地化名称):** SSN · SIN · NINO · NHS · TFN · Medicare · IRD · NRIC · MyKad · Aadhaar · PAN · CPF · CNPJ · CURP · RFC · Steuer-ID · NIR · BSN · DNI/NIE · Codice Fiscale · NIF · PESEL · Personnummer · Fødselsnummer · HETU · CPR · RRN · My Number · HKID · 身份证 · 居民身份证 · 身分證 · 香港身份證 · マイナンバー · 個人番号 · 주민등록번호 · ИНН · СНИЛС · บัตรประชาชน · ΑΦΜ · ΑΜΚΑ · आधार · CCCD. ## 安装 ``` dotnet add package RedactWire ``` ## 快速开始 有三种使用方式 — 选择最适合你应用的一种。 ### 1. 静态外观模式(零引导配置) ``` using RedactWire; PiiResult r = Redactor.Detect("My SSN is 123-45-6789"); bool hasPii = Redactor.HasPii("Call (415) 555-0132"); string clean = Redactor.Redact("Card 4242 4242 4242 4242"); ``` ### 2. 构建器模式(手动配置) ``` using System.Globalization; using RedactWire; var detector = PiiDetectorBuilder.CreateDefault() // invariant rules .AddCulture(new CultureInfo("en-US")) // en-US pack .UseOverlapStrategy(OverlapStrategy.KeepHighestConfidence) .Build(); PiiResult result = detector.Detect("Email john@x.co.nz, SSN 123-45-6789"); foreach (var m in result.AllMatches) Console.WriteLine($"{m.Severity} {m.Type} '{m.Value}' conf={m.Confidence:0.00}"); ``` ### 3. 依赖注入(ASP.NET Core / 通用主机) ``` // Program.cs builder.Services.AddRedactWire(b => b.AddCulture(new CultureInfo("en-US"))); // then inject PiiDetector anywhere public class MyService(PiiDetector detector) { /* detector.Detect(...) */ } ``` ## 结果 `Detect` 返回一个 `PiiResult`: - `Invariant` — 包含与国家无关的匹配结果的 `CulturePiiResult`(始终会被评估)。 - `Cultures` — 每个请求的文化对应一个 `CulturePiiResult`,每个包含: - `Matches`, `RulesEvaluated` - `Supported` — 是否为该文化找到了规则包? - `Passed` — `Supported && Matches.Count == 0` - `HasPii`, `AllMatches`(扁平化视图)。 每个 `PiiMatch` 都带有 `Type, Value, Start, Length, Confidence, Rule, Culture, Severity`。 ## 脱敏 ``` var r = Redactor.Detect("SSN 123-45-6789"); r.Redact(); // "SSN ***********" r.Redact(new RedactionOptions { Mode = RedactionMode.Label }); // "SSN [SocialSecurity]" r.Redact(new RedactionOptions { Custom = m => $"<{m.Type}>" }); ``` ## 验证 检查一个字符串是否完全是一个给定类型的有效 PII 项 — 使用与 检测相同的规则和校验和。返回 `Valid` / `Invalid` / `Unsupported`(最后一种情况被单独区分开来,这样“没有针对此类型/文化的规则”就不会被 误认为“无效”)。 ``` Redactor.Validate("123-45-6789", PiiType.SocialSecurity); // Valid Redactor.Validate("123-45-0000", PiiType.SocialSecurity); // Invalid Redactor.Validate("110101199001010015", new CultureInfo("zh-CN"), PiiType.NationalId); // Valid (GB11643) Redactor.Validate("x", new CultureInfo("fr-FR"), PiiType.NationalId); // Unsupported // PiiType.Custom needs a subtype: detector.Validate("112-233-445 95", new CultureInfo("ru-RU"), PiiType.Custom, "SNILS"); ``` 无文化参数的重载方法会根据检测器配置的文化进行验证;传入 `CultureInfo` 以指定特定文化。必须是全字符串匹配(忽略首尾空格)。 ## 密钥检测 API 密钥、token 和私钥 — 与国家无关,因此它们作为不变规则运行。 ``` var d = PiiDetectorBuilder.CreateDefault().AddSecretDetection().Build(); foreach (var m in d.Detect("OPENAI_API_KEY=sk-abc...xyz").AllMatches.Where(m => m.Type == PiiType.Secret)) Console.WriteLine(m.Subtype); // OpenAiKey Redactor.Redact("aws key AKIAIOSFODNN7EXAMPLE"); // "aws key ***************..." (secrets on by default) ``` 涵盖 OpenAI、AWS access-key-id、GitHub、Stripe、Slack、Google、SendGrid、npm、JWT 和 PEM 私钥(高精度,带有提供商前缀)。AWS *secret* keys / Azure keys / 连接字符串 需要熵/上下文支持,将留待后续阶段处理。参见 [`docs/rules/secrets.md`](docs/rules/secrets.md)。 ## 结构化扫描(JSON / XML / 对象) 扫描结构化数据并获取每个匹配项及其位置。可在 `PiiDetector` (以及静态 `Redactor`)上使用。 ``` foreach (var h in Redactor.DetectJson("""{"user":{"email":"a@b.com"},"ssn":"123-45-6789"}""")) Console.WriteLine($"{h.Path}: {h.Match.Type}"); // $.user.email: Email // $.ssn: SocialSecurity Redactor.DetectXml(""); // -> /u/@email Redactor.DetectObject(myPoco); // -> User.Contacts[0].Phone ``` 注意: - 仅扫描 **字符串** 值(丢失了格式信息的数字不是可靠的 PII)。 - XML 解析禁止了 DTD 处理且没有外部解析器 — **XXE 安全**。 - 对象扫描会遍历公共属性/字段,处理集合/字典, 检测循环,限制深度,并且不会递归进入框架类型。 - `System.Text.Json` 内置于现代 .NET 中;在 `netstandard2.0`/.NET Framework 上 它作为 NuGet 依赖项提供(该库采用多目标框架,因此 net8+ 依然保持整洁)。 ## 扩展 无需修改库即可添加自定义规则。`RegexRule` 已经涵盖了大多数需求: ``` var detector = PiiDetectorBuilder.CreateDefault() .AddCulture(new CultureInfo("en-US")) .AddRule(new CultureInfo("en-US"), // bind to one culture new RegexRule("EmployeeId", PiiType.NationalId, @"(?\bEMP\d{6}\b)", baseConfidence: 0.8, severity: PiiSeverity.Critical)) // optional; defaults from the type .AddInvariantRule(myGlobalRule) // always-on, culture-agnostic .Build(); ``` 对于单个正则表达式无法满足的需求,请实现 `IPiiRule`。规则只报告原始的 `RuleHit` — 引擎会自动标记文化、规则 ID 和默认的严重性级别,因此 不存在会出错的繁琐配置: ``` public sealed class MyRule : IPiiRule { public string Name => "MyRule"; public PiiType Type => PiiType.NationalId; public IEnumerable Find(string text) { // ... locate a match ... yield return new RuleHit(value, start, length, confidence: 0.9); // (pass a PiiSeverity to override the type default) } } var detector = PiiDetectorBuilder.CreateDefault() .AddCulture(new CultureInfo("en-US")) .AddCulture(new CultureInfo("en-GB")) .AddRule(new MyRule()) // bind to every configured culture at once .Build(); ``` ### 自定义 PII 类型 `PiiType` 是一个枚举(枚举无法被扩展)。对于列表中没有的类型,请使用 `PiiType.Custom` 并通过 `RuleHit.Subtype` 为其指定一个真实名称 — 该名称会流入 匹配结果和脱敏标签中: ``` yield return new RuleHit(value, start, length, 0.9, Severity: PiiSeverity.Critical, Subtype: "NhiNumber"); // match.Type == PiiType.Custom, match.Subtype == "NhiNumber" // Redact(Label) -> "[NhiNumber]" ``` ## 范围与路线图 - **基于 NER 的姓名和地址检测** 不在核心库内(正则表达式会产生大量误报)。 `Address` 规则是一种正则启发式方法;完整的人名检测保留给可选的 `RedactWire.Ner` 包(本地 ONNX,例如 GLiNER) — 单独保留是为了避免强制 每个使用者接受一个庞大的模型及其许可证。 - 将推出更多国家规则包(UK、DE/FR、AU/JP/SG/IN 等)。 ## 项目 | 路径 | 内容 | |---|---| | `src/RedactWire` | 库(+ DI 引导) | | `src/RedactWire.Cli` | 命令行扫描器 / 脱敏器 | | `samples/RedactWire.Sample.Web` | ASP.NET Core Razor Pages PII 测试器 | | `tests/RedactWire.Tests` | xUnit 测试 | | `docs/rules/` | 规则文档(`common.md`、`severity.md`、`localized/`) | ## CLI ``` echo "My SSN is 123-45-6789" | dotnet run --project src/RedactWire.Cli dotnet run --project src/RedactWire.Cli -- --redact --text "Card 4242 4242 4242 4242" ``` 当发现 PII 时退出代码为 `1`,干净时为 `0` — 在 CI 中非常实用。 ## 许可证 Apache License 2.0。参见 [LICENSE](LICENSE)。
标签:PII识别, 多人体追踪, 对抗攻击, 开发库, 敏感信息检测, 数据合规, 数据脱敏