NagaYu/local-pii-masking-api

GitHub: NagaYu/local-pii-masking-api

一个 100% 本地运行、零出口流量的 PII 脱敏与还原代理 API,用于在文本发送到云端 LLM 之前保护敏感个人数据。

Stars: 0 | Forks: 0

# 本地安全 Tokenizer 与 PII 脱敏 API [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/b86d9657bc160545.svg)](https://github.com/NagaYu/local-pii-masking-api/actions/workflows/ci.yml) [![Docker Publish](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/655b727d5c160547.svg)](https://github.com/NagaYu/local-pii-masking-api/actions/workflows/docker-publish.yml) [![Docker Hub](https://img.shields.io/docker/pulls/yuta713/local-pii-masking-api.svg)](https://hub.docker.com/r/yuta713/local-pii-masking-api) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/) 一个 **100% 本地设备运行的无头代理 API**,能够检测原始文本中的个人身份信息 (PII),并将其替换为确定性、可逆的 token —— 然后在返回时还原原始内容。 将它部署在任何外部 LLM(或任何第三方 API)的前端,即可构建一道坚固的**安全墙**:对外发的 prompt 进行脱敏,仅将 token 发送到云端,然后在本地对模型的回复进行还原。**您的敏感数据在物理上绝对不会离开宿主机。** ## 设计原则 | 原则 | 含义 | | --- | --- | | **100% 数据驻留** | 检测和 token 化完全在本地 CPU 上运行,使用正则表达式和轻量级验证器。该服务自身**不发起任何出站网络调用**。 | | **零知识网关代理** | token ↔ 原始内容的映射仅存在于进程内存中,并按会话划分作用域。下游系统(LLM、日志、分析)永远只能看到像 `[MASKED_EMAIL_1]` 这样的不透明 token。 | | **零外部基础设施成本** | 无需数据库、消息队列、云服务或模型下载。单个 container 即为完整的部署。 | | **确定性与可逆** | 在同一个会话中,相同的值始终产生相同的 token(从而保持 LLM prompt 的连贯性),并且每个 token 都能精确映射回其原始子字符串。 | | **内存受限** | 会话存储库会过期 (TTL),并发会话数量受 LRU 驱逐机制限制,且每个存储库都有大小上限 —— 因此持续的高吞吐量文档流不会导致内存泄漏。 | ## 检测范围 | 类别 | Token 示例 | 备注 | | --- | --- | --- | | 电子邮箱地址 | `[MASKED_EMAIL_1]` | | | 电话号码 | `[MASKED_PHONE_1]` | 7–15 位数字,支持国际/美国分组 | | 信用卡号 | `[MASKED_CREDIT_CARD_1]` | 通过 **Luhn** 校验和确认 | | IBAN | `[MASKED_IBAN_1]` | | | 美国 SSN | `[MASKED_SSN_1]` | | | IP 地址 | `[MASKED_IP_ADDRESS_1]` | IPv4,经过八位组验证 | | URL | `[MASKED_URL_1]` | | | 人名 | `[MASKED_PERSON_1]` | 启发式检测,仅限 **strict** 级别 | | 邮政地址 | `[MASKED_ADDRESS_1]` | 启发式检测,仅限 **strict** 级别 | ### 严格级别 - **`lenient`** — 仅检测明确的标识符(电子邮箱、信用卡、IBAN、SSN)。 - **`standard`** *(默认)* — lenient 集合 **+** 电话号码、IP 地址、URL。 - **`strict`** — standard 集合 **+** 启发式的人名和地址检测 (召回率最高,但可能产生误报)。 ## 快速开始(3 分钟) ### 选项 A — Docker(推荐) 拉取预构建的镜像(支持多架构:`linux/amd64`, `linux/arm64`): ``` docker run --rm -p 8080:8080 yuta713/local-pii-masking-api:latest ``` …或者从源码在本地构建: ``` docker build -t local-pii-api . docker run --rm -p 8080:8080 local-pii-api ``` ### 选项 B — 本地 Python (3.10+) ``` python -m venv .venv && source .venv/bin/activate pip install -r requirements.txt uvicorn app.main:app --host 127.0.0.1 --port 8080 ``` 然后打开交互式的全英文 API 文档: - **Swagger UI:** http://127.0.0.1:8080/docs - **健康检查:** http://127.0.0.1:8080/health 运行测试套件: ``` pip install -r requirements-dev.txt pytest -q ``` ## API 参考 ### `POST /api/v1/mask` **请求** ``` { "text": "Contact John Doe at john.doe@acme.com or +1 (415) 555-0132.", "strictness": "standard", "client_id": "support-bot-01", "session_id": null } ``` **响应** ``` { "masked_text": "Contact John Doe at [MASKED_EMAIL_1] or [MASKED_PHONE_1].", "session_id": "1c4f0b9e7c3a4a9e9d2f3a1b2c3d4e5f", "detections": 2, "detections_by_type": { "EMAIL": 1, "PHONE": 1 }, "latency_ms": 0.19 } ``` ### `POST /api/v1/unmask` **请求** ``` { "text": "I've emailed [MASKED_EMAIL_1] and called [MASKED_PHONE_1].", "session_id": "1c4f0b9e7c3a4a9e9d2f3a1b2c3d4e5f" } ``` **响应** ``` { "unmasked_text": "I've emailed john.doe@acme.com and called +1 (415) 555-0132.", "restored": 2, "latency_ms": 0.02 } ``` 如果会话未知或已过期,则返回 **404**(原始内容已无法恢复;需重新对源文本进行脱敏)。 ### `GET /health` ``` { "status": "ok", "version": "1.0.0", "active_sessions": 3, "uptime_seconds": 1287.4 } ``` ## 作为云端 LLM 前端的安全墙使用 该模式始终是相同的三个步骤:**mask → 调用云端 → unmask**。 ``` import requests GATEWAY = "http://127.0.0.1:8080" raw_prompt = ( "Summarize this ticket from John Doe (john.doe@acme.com, " "+1 (415) 555-0132): the customer cannot log in." ) # 1) 在本地 MASK — 在任何数据离开大楼之前剥离 PII。 m = requests.post( f"{GATEWAY}/api/v1/mask", json={"text": raw_prompt, "client_id": "ticket-summarizer"}, ).json() safe_prompt = m["masked_text"] # contains only tokens, no PII session_id = m["session_id"] # 2) 仅使用已净化的 prompt CALL THE CLOUD。 # (将其替换为您提供商的 SDK / HTTP 调用) cloud_reply = call_your_favorite_cloud_llm(safe_prompt) # 例如 -> "I've drafted a reply to [MASKED_EMAIL_1] about the login issue." # 3) 在本地 UNMASK 响应以恢复真实值。 u = requests.post( f"{GATEWAY}/api/v1/unmask", json={"text": cloud_reply, "session_id": session_id}, ).json() print(u["unmasked_text"]) # -> "I've drafted a reply to john.doe@acme.com about the login issue." ``` ``` # 使用 curl 的相同流程: curl -s -X POST http://127.0.0.1:8080/api/v1/mask \ -H "Content-Type: application/json" \ -d '{"text":"Email john.doe@acme.com","client_id":"cli"}' ``` ## 配置 所有设置均为环境变量,并提供生产安全的默认值: | 变量 | 默认值 | 描述 | | --- | --- | --- | | `PORT` | `8080` | 监听端口(container)。 | | `PII_SESSION_TTL_SECONDS` | `3600` | 会话存储库在被清除前的空闲生命周期。 | | `PII_MAX_SESSIONS` | `10000` | 最大并发存储库;超出此数量时将驱逐最旧(LRU)的存储库。 | | `PII_MAX_ENTRIES_PER_SESSION` | `50000` | 每个存储库可存储的最大不同值数量。 | | `PII_SWEEP_INTERVAL_SECONDS` | `60` | 后台清理程序清除过期存储库的频率。 | ## 范围与限制 本项目是一个**开源 MVP / 参考实现**。它在设计上有意保持轻量和极少的依赖。在依赖它之前,请了解以下边界: - **单进程状态。** 会话存储库存在于单个进程的内存中。 请使用**单个 worker** 运行(默认设置)。运行多个 Uvicorn/Gunicorn worker —— 或多个副本 —— 会将 `mask` 和 `unmask` 路由到不同的 进程,从而破坏还原机制。横向扩展需要共享存储(例如 Redis);这超出了本项目的范围。 - **以英语/美国为中心的检测。** 检测器针对电子邮件、电话、信用卡、IBAN、SSN、IP、URL 以及(启发式地)英文姓名和美国地址。它们**不**涵盖特定语言环境的标识符,例如日本的 My Number(个人编号)、日本的电话/邮政编码格式或非拉丁字母姓名。 - **基于正则表达式的尽力而为。** 检测以牺牲完整性来换取速度和零依赖。预期会出现漏报和误报,尤其是在启发式的 `strict` 级别姓名/地址检测器中。这是一种纵深防御,**而非**合规保证。 - **无内置身份验证或速率限制。** 请将其部署在您自己的身份验证/网关之后,并保持在受信任的本地/专用网络中。 ## 安全说明 - **无出站流量。** 该服务从不发起外部连接。您可以将其运行在气隙网络中,或者完全阻断其出站防火墙。 - **CORS 已被锁定**,仅限回环地址和 RFC-1918 私有网段 (`localhost`, `127.0.0.0/8`, `10/8`, `172.16/12`, `192.168/16`, `[::1]`)。 绝对不允许任何公共来源访问。 - **纯内存映射。** Token ↔ 原始内容的映射永远不会写入磁盘。重启进程后,所有机密信息都会随之消失。 - **纵深防御,而非万灵药。** 启发式检测器(姓名、 地址)以牺牲精确度来换取召回率。请选择适合您风险承受能力的严格级别,并将此网关置于您自己的身份验证之后。 ## 架构 ``` ┌─────────────────────────── your host / private LAN ───────────────────────────┐ │ │ raw text ──┼──► POST /api/v1/mask ──► engine.py (regex + Luhn, 100% local) │ │ │ │ │ ▼ │ │ in-memory session vault (TTL + LRU bounded) │ │ │ │ tokens ◄──┼──────────────────────────────┘ │ │ │ │ │ └──► (you send tokens to any external LLM — no PII crosses the boundary) │ │ │ LLM reply ─┼──► POST /api/v1/unmask ──► restore via vault ──► original values returned │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ ``` | 文件 | 职责 | | --- | --- | | `app/schemas.py` | 严格的 Pydantic v2 请求/响应契约与验证。 | | `app/engine.py` | 设备端 PII 检测器、确定性 tokenizer、有界存储库。 | | `app/main.py` | FastAPI 应用:CORS 锁定、`/health`、`/mask`、`/unmask`、OpenAPI 文档。 | | `tests/test_api.py` | 单元测试与 HTTP 集成测试(检测、往返测试、内存边界)。 | | `Dockerfile` | 多阶段、非 root 用户、带有健康检查的生产级镜像。 | ## 许可证 基于 [MIT 许可证](LICENSE) 发布。
标签:API代理, AV绕过, DLL 劫持, FastAPI, Python, 大语言模型, 数据脱敏, 无后门, 网络安全, 请求拦截, 逆向工具, 隐私保护