adamy/RedactWire
GitHub: adamy/RedactWire
一款专为 .NET 设计的轻量级 PII 检测与脱敏库,支持基于校验和验证的跨国身份证件与敏感数据扫描。
Stars: 0 | Forks: 0
# RedactWire
[](https://www.nuget.org/packages/RedactWire/)
[](https://github.com/adamy/RedactWire/actions/workflows/ci.yml)
[](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识别, 多人体追踪, 对抗攻击, 开发库, 敏感信息检测, 数据合规, 数据脱敏