grounzero/pfsense-redactor
GitHub: grounzero/pfsense-redactor
专门针对 pfSense config.xml 导出文件进行机密信息脱敏与网络标识符匿名化的命令行工具,用于安全地共享配置。
Stars: 11 | Forks: 0
# pfSense XML 配置脱敏工具
[](https://pypi.org/project/pfsense-redactor/)
[](https://pypi.org/project/pfsense-redactor/)
[](https://opensource.org/licenses/MIT)
[](https://github.com/grounzero/pfsense-redactor/actions/workflows/tests.yml)
[](https://pepy.tech/project/pfsense-redactor)
安全地脱敏 pfSense `config.xml` 导出文件中的敏感字段,让您在分享时不会暴露密码、密钥或网络标识符。
**关键词:** pfSense config.xml 脱敏工具、pfSense 清理器、防火墙配置清理、VPN 配置匿名化、OpenVPN 脱敏、WireGuard 密钥脱敏、IPsec 密钥移除、网络拓扑匿名化工具、Netgate TAC 共享
**pfsense-redactor** 会对 pfSense `config.xml` 导出文件中的机密信息进行脱敏,并可选择对标识符进行匿名化处理——以便您可以安全地将其分享给技术支持、供应商、审计人员、论坛或 AI 工具。
与通用的 XML 脱敏工具不同,pfsense-redactor 深入理解 pfSense 特定的配置结构和 VPN 格式。
## 为什么选择 pfsense-redactor?
- ✅ **pfSense 原生支持** – 深入理解 pfSense XML 结构(IPsec、OpenVPN、WireGuard、软件包)
- ✅ **零依赖** – 纯 Python 标准库,可在任何地方运行(Windows、macOS、Linux)
- ✅ **经过充分测试** – 在多种操作系统和 Python 版本上进行了全面测试
- ✅ **保留拓扑** – 匿名化而不破坏路由逻辑或防火墙规则
- ✅ **安全至上** – 内置防止路径遍历和符号链接攻击的保护措施
- ✅ **适配 CI/CD** – 适用于自动化合规工作流和 GitOps
## 何时使用 pfsense-redactor?
当您需要在防火墙外部共享 pfSense `config.xml` 文件时(例如与供应商、顾问、论坛或 AI 工具共享),并且希望在不破坏拓扑或路由逻辑的前提下移除机密信息和/或对网络标识符进行匿名化处理,请使用 pfsense-redactor。
### 快速开始(推荐)
#### 1) 保留私有 IP(最适合技术支持 / 故障排查)
```
pfsense-redactor config.xml redacted.xml --keep-private-ips
```
保持内部寻址可见,同时移除机密信息并对公共标识符进行脱敏。
#### 2) 保留拓扑的匿名化(最适合供应商 / 论坛 / AI)
```
pfsense-redactor config.xml redacted.xml --anonymise
```
使用一致的占位符替换标识符,这样在降低信息泄露风险的同时,仍能保持清晰的关系。
关于在 pfSense 防火墙本机进行的清理,请参阅下文的 `diag_sanitize.php`;pfsense-redactor 专为脱机使用和匿名化而设计。
有关所有可用选项,请参阅下方的[用法](#usage)部分和[命令行参数参考](#command-line-flags-reference)。
## 使用场景
根据您的分享对象,这里提供了常见的命令模式。
### 与 Netgate TAC 技术支持共享
```
# 在防火墙上(推荐用于 TAC)
/usr/local/sbin/diag_sanitize.php /conf/config.xml > /conf/config_sanitised.xml
# Off-box:在进一步共享之前进行额外的匿名化
pfsense-redactor config_sanitised.xml support-safe.xml --keep-private-ips --no-redact-domains
```
### 与 AI 工具共享
如果您安装了第三方软件包,或者不确定机密信息隐藏在哪里,请使用 `--aggressive`。
```
# 保持拓扑结构的匿名化(使用 --anonymise 时,默认保持 private IP 可见)
pfsense-redactor config.xml ai-ready.xml --anonymise --aggressive
# 现在可以安全地上传到 AI 工具进行配置分析
```
```
# 匿名化所有内容(包括 private IP)
pfsense-redactor config.xml ai-ready.xml --anonymise --no-keep-private-ips --aggressive
# 现在可以安全地上传到 AI 工具进行配置分析
```
### 交付给供应商/MSP
```
# 选项 A:保留 private IP 以用于故障排查上下文
pfsense-redactor config.xml vendor-share.xml --anonymise
```
```
# 选项 B:匿名化所有内容(包括 private IP)以实现更严格的隐私保护
pfsense-redactor config.xml vendor-share.xml --anonymise --no-keep-private-ips
```
### 安全审计
```
# 在共享前预览将被脱敏的内容
pfsense-redactor config.xml --dry-run-verbose
```
### 自动化合规工作流
```
# CI/CD 集成以实现自动化脱敏
pfsense-redactor $INPUT_CONFIG $OUTPUT_CONFIG --aggressive --fail-on-warn
```
## 与 pfSense 内置清理功能的关系
pfSense 包含一个内置的配置清理脚本:
```
/usr/local/sbin/diag_sanitize.php /conf/config.xml > /conf/config_sanitised.xml
```
这个官方工具**在防火墙本机**运行,主要用于安全地与 Netgate 技术支持共享配置。它会移除高价值机密(密码哈希、预共享密钥、证书等),同时保留原始网络拓扑。
**pfsense-redactor 是互补工具,而非替代品。**
| 内置的 `diag_sanitize.php` | pfsense-redactor |
| ------------------------------------ | ----------------------------------------------------------------- |
| 仅在 pfSense 上运行 | 可在任何地方运行(工作站、CI、自动化环境) |
| PHP 编写,pfSense 内部组件 | Python 编写,独立运行,基于 MIT 许证证 |
| 固定的清理行为 | 可配置的脱敏与匿名化规则 |
| 移除机密信息 | 移除机密信息,**并且**可以对 IP、域名、MAC 地址和 URL 进行匿名化 |
| 最适合 Netgate 技术支持 (TAC) | 最适合分享给供应商、顾问、AI 工具和论坛 |
pfsense-redactor 的存在是为了涵盖以下使用场景:
- 配置文件已经导出,
- 您不希望在防火墙上运行额外的工具,
- 或者除了基本的机密移除外,您还需要**保护隐私的匿名化**。
这两个工具的目标一致:在共享 pfSense 配置时,防止意外泄露敏感信息。
## 与替代方案对比
## 常见问题
### pfsense-redactor 默认会脱敏哪些内容?
pfsense-redactor 会移除诸如密码、私钥、证书、token 和共享密钥等机密信息。
除非明确要求保留,否则它也会对公共 IP 地址、域名、MAC 地址和 URL 进行脱敏。
### pfsense-redactor 是进行匿名化还是仅仅移除数据?
两者都支持。脱敏会彻底移除敏感值,而匿名化则会使用一致的占位符替换标识符,从而保持拓扑和关系的清晰。
### 匿名化会破坏故障排查或拓扑分析吗?
不会。确定性的匿名化确保相同的标识符始终被替换为相同的别名,从而保留逻辑关系和路由流。
### 我可以安全地将输出结果分享给供应商或 AI 工具吗?
可以。pfsense-redactor 专为对外共享配置而设计,不会暴露机密或可识别的网络信息。
脱敏后的输出仅供分析使用,切勿将其恢复至 pfSense。
### 它能理解 pfSense 特定的配置结构吗?
能。与通用的 XML 脱敏工具不同,pfsense-redactor 理解 pfSense 的配置布局,包括 VPN、接口、网关以及常见的软件包 XML 结构。
### 什么时候应该使用 aggressive 模式?
当公开发布配置或第三方软件包可能包含未知的敏感字段时,请使用 `--aggressive`。
aggressive 模式扩大了机密检测和标识符重写的范围。在默认行为的基础上,它还会:
- 对任意元素中无法识别的高熵值(base64/hex/PEM 格式)进行脱敏,而不是仅仅将其报告出来
- 直接对自由文本选项块(`custom_options`、`userparams`、`upsd_users`、`advanced` 等)进行整体脱敏
- 对包含凭据格式的 URL **路径**段进行脱敏,例如 Slack/Discord 的 webhook token
- 将 IP/域名脱敏应用于所有元素文本,而不仅仅是已知字段
### 我可以将脱敏后的文件恢复到 pfSense 吗?
不能。脱敏后的输出仅供分析/共享使用,绝不能重新导入 pfSense。
## 安装说明
### 通过 PyPI 安装(推荐)
```
pip install pfsense-redactor
```
### 通过源码安装
```
git clone https://github.com/grounzero/pfsense-redactor.git
cd pfsense-redactor
```
**选项 1:开发模式(推荐用于参与贡献)**
```
pip install -e .
```
**选项 2:使用虚拟环境**
```
python3 -m venv venv
source venv/bin/activate
pip install -e .
```
该工具在清理**机密信息和标识符**的同时,会保留**网络架构和路由逻辑**,从而允许进行安全的故障排查和拓扑审查而不会泄露私有数据。
## 功能
### 保护真实的机密信息
- 密码和加密密码
- 预共享密钥(IPSec、OpenVPN、WireGuard)
- TLS/OpenVPN 静态密钥和证书
- SNMP community 字符串
- LDAP / RADIUS 密钥
- API 密钥和 token
- PEM 块(RSA / EC / OpenSSH)
### 保留网络逻辑
- 子网和掩码(255.x.x.x 始终保留)
- 路由器拓扑
- VLAN 和 VPN 接口
- 防火墙规则和网关
### 智能脱敏
| 数据 | 行为 |
| ---------------- | ----------------------------------- |
| 内部 IP | 使用 `--keep-private-ips` 保留 |
| 公共 IP | 掩码或匿名化 |
| 电子邮件地址 | 掩码或匿名化 |
| URL | 保留结构,对主机名掩码处理 |
| MAC 地址 | 掩码并保持格式 |
| 证书 | 折叠为 `[REDACTED_CERT_OR_KEY]` |
### 操作模式
| 模式 | 用途 |
| ----------------------- | ------------------------------------------------------------------- |
| 默认 | 用于安全地共享日志的脱敏模式 |
| `--keep-private-ips` | 保留私有 IP(最适合支持/AI) |
| `--anonymise` | 用一致的占位符替换标识符(`IP_1`、`domain3.example`) |
| `--aggressive` | 清理**所有**字段(插件/自定义 XML) |
| `--redact-descriptions` | 同时脱敏描述、主机名和 SSID(可能包含个人姓名) |
## 环境要求
- **Python 3.9+**
## 用法
### 基本用法
```
# 输出文件名自动生成为 config-redacted.xml
pfsense-redactor config.xml
# 或显式指定输出文件名
pfsense-redactor config.xml redacted.xml
```
### 保留私有 IP(推荐)
```
pfsense-redactor config.xml redacted.xml --keep-private-ips
```
### 将特定 IP 和域名加入白名单
```
# 保留特定的 public service(绝不通脱敏)
pfsense-redactor config.xml --allowlist-ip 8.8.8.8 --allowlist-domain time.nist.gov
# 保留整个 CIDR 范围
pfsense-redactor config.xml --allowlist-ip 203.0.113.0/24
# 使用 allow-list 文件(支持 IP、CIDR 和 domain)
pfsense-redactor config.xml --allowlist-file my-allowlist.txt
```
### 保持拓扑安全的匿名化
```
pfsense-redactor config.xml redacted.xml --anonymise
```
### 允许内部 DNS 名称
```
pfsense-redactor config.xml redacted.xml --no-redact-domains --keep-private-ips
```
### aggressive 模式
```
pfsense-redactor config.xml redacted.xml --aggressive
```
### 试运行
```
# 仅显示统计信息
pfsense-redactor config.xml --dry-run
# 显示统计信息和脱敏样本(已安全掩码)
pfsense-redactor config.xml --dry-run-verbose
```
### 输出到 STDOUT
```
pfsense-redactor config.xml --stdout > redacted.xml
```
### 原地覆盖(危险)
```
pfsense-redactor config.xml --inplace --force
```
## 命令行参数参考
### 版本与帮助
| 参数 | 描述 |
| ---------------- | ---------------------------- |
| `--version` | 显示程序版本并退出 |
| `--check-version`| 检查 PyPI 上的更新 |
| `-h, --help` | 显示帮助信息并退出 |
### 输入/输出
| 参数 | 描述 |
| ------------------------ | ------------------------------------------------------------------------------------------------------- |
| `input` | 输入的 pfSense config.xml 文件(位置参数) |
| `output` | 输出的脱敏 config.xml 文件(位置参数,使用 `--stdout`/`--dry-run`/`--inplace` 时可选) |
| `--stdout` | 将脱敏后的 XML 输出到 stdout 而非文件 |
| `--inplace` | 用脱敏后的输出覆盖输入文件(请谨慎使用) |
| `--force` | 如果输出文件已存在则强制覆盖 |
| `--allow-absolute-paths` | 允许绝对文件路径(出于安全考虑,默认仅允许相对路径) |
### 脱敏模式
| 参数 | 描述 |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `--keep-private-ips` | 保持非全局 IP 地址可见(RFC198/ULA/回环/链路本地)。子网掩码和未指定地址(0.0.0.0, ::)始终保留 |
| `--no-keep-private-ips` | 与 `--anonymise` 配合使用时,不保留私有 IP 的可见性(掩码处理所有 IP) |
| `--anonymise` | 使用一致的别名(IP_1, domain1.example)来保留网络拓扑。除非指定 `--no-keep-private-ips`,否则隐含 `--keep-private-ips` |
| `--aggressive` | 扩大机密检测范围(高熵值、自由文本选项块、URL 路径 token),并对所有元素文本应用 IP/域名脱敏 |
| `--no-redact-ips` | 不对 IP 地址进行脱敏 |
| `--no-redact-domains` | 不对域名进行脱敏 |
| `--redact-url-usernames` | 脱敏 URL 中的用户名(默认:保留用户名,始终脱敏密码) |
| `--redact-descriptions` | 脱敏自由文本描述和标识符(`descr`, `detail`, `hostname`, `ssid`)。默认关闭,因为这些信息有助于故障排查 |
### 输出控制
| 参数 | 描述 |
| --------------- | ---------------------------------------------------------- |
| `-q, --quiet` | 隐藏进度信息(仅显示警告和错误) |
| `-v, --verbose` | 显示详细的调试信息 |
## 白名单
白名单允许您保留特定的、不会泄露隐私信息的知名 IP 和域名。
### 默认白名单文件
该工具会自动从以下位置加载白名单(如果存在):
1. 当前目录下的 `.pfsense-allowlist`
2. 家目录中的 `~/.pfsense-allowlist`
禁用方法:使用 `--no-default-allowlist`
### 白名单文件格式
创建 `.pfsense-allowlist` 或使用 `--allowlist-file`:
```
# 注释以 # 开头
# 每行一个条目(IP、CIDR 或 domain)
# 公共 DNS 服务器
8.8.8.8
1.1.1.1
# Cloud provider 范围
203.0.113.0/24
198.51.100.0/24
# NTP 服务器(后缀匹配:保留 time.nist.gov 和 *.time.nist.gov)
time.nist.gov
pool.ntp.org
# 通配符 domain(*.example.org 保留所有子域名)
*.pfsense.org
```
有关完整的模板,请参见 [`allowlist.example`](allowlist.example)。
### 命令行白名单参数
```
# 添加特定的 IP 或 CIDR 范围(可重复)
--allowlist-ip 8.8.8.8 --allowlist-ip 203.0.113.0/24
# 添加特定的 domain(可重复、不区分大小写、支持后缀匹配)
--allowlist-domain time.nist.gov --allowlist-domain pool.ntp.org
# 从文件加载(支持 IP、CIDR 和 domain)
--allowlist-file /path/to/allowlist.txt
# 禁用默认文件加载
--no-default-allowlist
```
**特性:**
- **支持 CIDR**:`203.0.113.0/24` 将保留该范围内的所有 IP
- **后缀匹配**:`example.org` 将保留 `sub.example.org`、`db.corp.example.org` 等。
- **通配符域名**:`*.example.org` 等同于对 `example.org` 的后缀匹配
- **IDNA/punycode**:自动处理国际化域名(例如,`bücher.example` ↔ `xn--bcher-kva.example`)
- **合并来源**:所有命令行参数、文件和默认文件都会被合并处理
**注意:** 白名单中的项目在以下位置绝不会被脱敏:
- 文本中的 IP/域名引用
- URL 主机名
- 裸 FQDN
## 示例
### 输入
```
192.168.10.1
-----BEGIN OpenVPN Static key-----ABC123...
198.51.100.10
443
```
### 输出(`--keep-private-ips`)
```
192.168.10.1
[REDACTED]
XXX.XXX.XXX.XXX
443
```
### 输出(`--anonymise`)
```
IP_1
[REDACTED]
IP_2
443
```
## 安全说明
脱敏后的输出**仅供分析**,因为:
- CDATA 和注释会被 XML 解析器移除
- PEM 块和二进制数据会被折叠
- 某些可选的元数据字段可能会被剔除
请务必妥善保管**原始的安全副本**。
### 路径安全
该工具内置了防范恶意文件路径操作的保护措施:
**默认行为(安全):**
- 默认仅允许相对路径
- 阻止目录遍历(`../../../etc/passwd`)
- 拒绝包含空字节的路径
- 阻止写入系统目录(`/etc`、`/sys`、`/proc`、`/Windows/System32` 等)
- 自动允许安全位置(家目录、当前工作目录、临时目录)
**使用 `--allow-absolute-paths` 时:**
- 为特定的使用场景启用绝对路径
- 仍然阻止写入敏感的系统目录
- 仍然阻止目录遍历尝试
- 适用于需要显式指定完整路径的情况
**示例:**
```
# 安全:相对路径(默认)
pfsense-redactor config.xml output.xml
# 已阻止:不带 flag 的绝对路径
pfsense-redactor /etc/config.xml output.xml
# 错误:不允许绝对路径(请使用 --allow-absolute-paths)
# 已阻止:目录遍历
pfsense-redactor ../../../etc/passwd output.xml
# 错误:路径包含目录遍历组件(..)
# 已阻止:写入系统目录(即使带有 flag)
pfsense-redactor config.xml /etc/output.xml --allow-absolute-paths
# 错误:无法写入敏感系统目录
# 允许:使用 flag 指向安全位置的绝对路径
pfsense-redactor ~/config.xml ~/output.xml --allow-absolute-paths
# 已阻止:原地编辑系统文件
pfsense-redactor /etc/hosts --inplace --force --allow-absolute-paths
# 错误:无法对此文件使用 --inplace
```
**受保护的系统目录:**
- Unix/Linux: `/etc`, `/sys`, `/proc`, `/dev`, `/boot`, `/root`, `/bin`, `/sbin`, `/usr/bin`, `/usr/sbin`, `/lib`, `/lib64`, `/var/log`, `/var/run`, `/tmp`, `/run`
- Windows: `C:\Windows`, `C:\Windows\System32`, `C:\Program Files`, `C:\ProgramData`
- 关键文件:`/etc/passwd`, `/etc/shadow`, `/etc/sudoers` 等。
## 测试
### 试运行摘要
```
# 仅显示统计信息
pfsense-redactor config.xml --dry-run
# 显示统计信息和脱敏样本(已安全掩码以避免泄露)
pfsense-redactor config.xml --dry-run-verbose
```
**使用 `--dry-run-verbose` 的示例输出:**
```
[+] Redaction summary:
- Passwords/keys/secrets: 10
- Certificates: 6
- IP addresses: 26
- Domain names: 47
[+] Samples of changes (limit N=5):
IP: 198.51.***.42 → XXX.XXX.XXX.XXX
IP: 2001:db8:*:****::1 → XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX
URL: https://198.51.***.42/admin → https://XXX.XXX.XXX.XXX/admin
FQDN: db.***.example.org → example.com
MAC: aa:bb:**:**:ee:ff → XX:XX:XX:XX:XX:XX
Secret: p****************d (len=18) → [REDACTED]
Cert/Key: PEM blob (len≈2048) → [REDACTED_CERT_OR_KEY]
```
**示例掩码策略**(防止在试运行输出中泄露信息):
- **IP**:保留首尾八位组/段,掩码中间部分(例如,`198.51.***.42`)
- **URL**:显示完整 URL,但按上述方式掩码主机
- **FQDN**:保留 TLD 和左侧一个标签,掩码其余部分(例如,`db.***.example.org`)
- **MAC**:掩码中间的八位组(例如,`aa:bb:**:**:ee:ff`)
- **机密信息**:仅显示长度和首尾 2 个字符(例如,`p****************d (len=18)`)
- **证书/密钥**:仅显示带有长度的占位符(例如,`PEM blob (len≈2048)`)
### 推荐的测试参数
| 用途 | 命令 |
| ---------------------------- | ---------------------------------------- |
| 支持与 AI 审查 | `--keep-private-ips --no-redact-domains` |
| 无标识符的拓扑图 | `--anonymise` |
| 彻底清除所有信息 | `--aggressive` |
## 统计示例
```
[+] Redaction summary:
- Passwords/keys/secrets: 4
- Certificates: 2
- IP addresses: 11
- MAC addresses: 3
- Domain names: 5
- Email addresses: 1
- URLs: 2
```
## 参与贡献
欢迎提交 Pull request。特别是关于:
- 扩展 pfSense 元素的覆盖范围
- 插件 XML 标签包(WireGuard、pfBlockerNG、HAProxy、Snort、ACME、FRR)
- 单元测试配置
## 许可证
MIT
与替代方案对比
| 功能 | pfsense-redactor | 通用 XML 工具 | 手动脱敏 | 内置 diag_sanitize.php | | ----------------------- | ----------------- | ----------------- | ---------------- | -------------------------- | | 感知 pfSense 结构 | ✅ | ❌ | ⚠️ 手动 | ✅ | | 支持脱机运行 | ✅ | ✅ | ✅ | ❌ (仅限 pfSense) | | 网络匿名化 | ✅ | ❌ | ⚠️ 容易出错 | ❌ | | 保持拓扑结构 | ✅ | ❌ | ⚠️ 容易出错 | ✅ | | 可配置模式 | ✅ 多种模式 | ❌ | 不适用 | ❌ 固定模式 | | CIDR 白名单 | ✅ | ❌ | ⚠️ 容易出错 | ❌ | | CI/CD 集成 | ✅ | ⚠️ | ⚠️ 容易出错 | ❌ | | 跨平台支持 | ✅ | ⚠️ | ✅ | ❌ | | 感知 WireGuard/IPsec | ✅ | ❌ | ⚠️ | ✅ | | 零依赖 | ✅ | ⚠️ 视情况而定 | ✅ | ✅ |白名单
- 白名单允许您保留特定的、不会泄露隐私信息的知名 IP 和域名。 | 参数 | 描述 | | --------------------------- | ------------------------------------------------------------------------------------------------------------------------ | | `--allowlist-ip IP_OR_CIDR` | 从不脱敏的 IP 地址或 CIDR 网络(可重复使用)。适用于文本和 URL | | `--allowlist-domain DOMAIN` | 从不脱敏的域名(可重复使用,不区分大小写,支持后缀匹配)。适用于裸 FQDN 和 URL 主机名 | | `--allowlist-file PATH` | 包含从不脱敏的 IP、CIDR 网络和域名的文件(每行一个) | | `--no-default-allowlist` | 不加载默认的白名单文件(当前目录或 ~/.pfsense-allowlist 中的 .pfsense-allowlist) |测试与诊断
| 参数 | 描述 | | ------------------- | ----------------------------------------------------------------------- | | `--dry-run` | 仅显示统计信息,不写入输出文件 | | `--dry-run-verbose` | 显示带有脱敏示例的统计信息(安全掩码处理以防止泄露) | | `--fail-on-warn` | 如果根标签不是 'pfsense',则以非零代码退出(在 CI 中很有用) |标签:pfSense, Python, XML处理, 数据隐私, 无后门, 运维工具, 逆向工具, 配置脱敏, 防火墙配置