mcpField
A
anonymize-logs

anonymize-logs

github.com/elastic安全16511 次安装5 周前更新
代码仓库

关于 anonymize-logs

用于在分享或提交前清理客户提供的日志文件或单行日志。它替换可识别身份的信息,同时保留原有结构和格式。

主要功能

  1. 01清理日志文件和单行日志
  2. 02保留分隔符、引号和字段顺序
  3. 03维持换行和输入形态
  4. 04对重复内容使用一致替换
  5. 05检查残留标识信息

适用场景

  1. 01准备可分享的客户日志
  2. 02提交日志样例前移除标识信息

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/elastic/integration-skills --skill anonymize-logs

安装后在 Claude Code 中输入/anonymize-logs确认已加载。

详细介绍

日志匿名化

清理客户提供的日志,使其可以安全地分享或提交。仅替换身份信息;保留原始结构、分隔符、引号、字段顺序和换行。

输入可以是文件,也可以是单行 syslog / KV / NDJSON。输出必须保持相同格式——不要在清理过程中美化排版、换行、截断或“修正”值。

你需要提供的内容

输入提供方式
要清理的日志文件使用 @ 提及文件,或直接粘贴
输出位置(可选)自由文本路径,默认为同一目录下添加 .sanitized 后缀
覆盖原文件(可选)说“原地覆盖”

黄金规则——绝不重新格式化内容

只替换敏感值。不要改动其他任何内容。

解析器和审阅日志的人员都依赖精确的空格、分隔符、引号和行结构。

  • NDJSON(每行一个 JSON 对象):不要美化排版、重新缩进或重构。每行必须保持为一个紧凑的 JSON 对象,且仅占一行。
  • Syslog / CEF / 键值日志:不要添加或删除空格、改变引号或规范化字段顺序。
  • 多行日志:严格保留原有的行分组。
  • 只替换标识真实个人、系统或组织的值——保留字段名、分隔符、结构标记及其他所有字符。
  • 不要添加、删除或重写 syslog PRI / RFC5424 标头。不要为了“看起来更像 syslog”而在不带标头的行前加上 <134>(或任何 PRI)。
  • 截断绝不是匿名化手段。 不要删除重复字段、丢弃末尾的 KV 键值对,或截断行的剩余部分来“完成”清理。请使用两遍映射法。

工作流程

步骤 1 — 两轮替换

不要边读边替换。将不同原文替换成同一个占位符,或只替换首次出现的内容而遗漏后续副本,这两种情况都不允许。

  1. 扫描整个文件/行,并为每个敏感令牌建立映射:原始值 → 占位符(包括嵌套值:URL 查询参数、复合 ID 中的十六进制双字、路径段)。
  2. 如果两个原始值不同,必须使用不同的占位符。如果它们相同,必须使用相同的占位符。
  3. 在全局范围内应用映射(替换所有出现的内容)。
  4. 再次扫描,检查是否有遗漏(URL 中的 IP、供应商 ID 中的十六进制 IP、看起来像产品名的主机名)。

至少涵盖:

  • 身份验证信息:API 密钥、Bearer 令牌、密码、OAuth 令牌、Base64 编码的凭据、私钥和证书(PEM 块、SSH 私钥)、TLS/SSH 指纹(JA3/JA4 哈希、SSH 主机密钥指纹、证书指纹)、DHCP 指纹、部分机密信息(token_prefix、password_hash_prefix、hashed_token)——部分暴露仍可识别凭据
  • 个人标识符:电子邮件地址(包括 CC/BCC 列表、委托人/所有者/创建者电子邮件变体)、用户名、显示名称、员工 ID、电话号码、主体名称(例如 [email protected])、电子邮件主题和正文
  • 组织标识符:公司名称、租户 ID(包括 home_tenant_id、resource_tenant_id、aad_tenant_id 变体)、账户 ID、订阅 ID、计费账户 ID、嵌入路径或 JSON 字段中的组织 slug、组织单元路径(例如 orgunit_path、org_unit_path)、部门名称和 ID、成本中心 ID、管道名称、任务名称或注册表路径中的 Windows SID(安全标识符)
  • 基础设施标识符:内部主机名、FQDN、私有 IP 地址、MAC 地址、内部 URL(暂存/生产环境主机名、内部工具域名)、云资源 ID(ARN、S3 存储桶名称、GCP 项目 ID、Azure 订阅/资源名称)、Kubernetes 集群名称、节点名称、Pod 名称和命名空间名称、容器名称和 ID、数据库主机名和名称(包括 database.host、database.name、database_principal_name)、Windows 域拓扑字段(域控制器主机名、NT 域名、domain_controller_object_guid、domain_controller_object_sid)
  • 设备和硬件标识符:序列号、硬件 UUID、机器 ID、设备 UUID、可唯一识别特定设备的 BIOS/固件版本字符串,包括 device_id/serial/类似字段中的值
  • 文件系统路径:嵌入用户名、组织名称或内部系统结构的进程命令行、文件路径、注册表项路径和日志文件路径(例如 C:\Users\alice\、/home/bob/、HKLM\...\S-1-5-21-...)
  • 连接字符串:数据库 URI、Redis URL,以及任何包含凭据或内部主机名的连接字符串
  • 资源所有权:所有者电子邮件、创建者电子邮件、最后修改者身份、委托用户电子邮件、受派人电子邮件、模拟者字段——任何用于标明资源操作人员身份的字段
  • 跟踪标识符:会话 ID、请求/关联 ID、事务 ID,或与真实实体关联的任何长不透明字符串
  • 哈希值:可能由敏感输入推导出的哈希值(密码哈希、HMAC 密钥)——保留文件哈希(文件内容的 MD5、SHA1、SHA256)和其他内容寻址引用(git SHA、用作标识符的 TLS 证书哈希)
  • 地理位置信息:精确 GPS 坐标、实际街道地址——地理信息增强字段中的城市和国家名称通常可以保留。清单或拓扑字段中的城市/站点令牌(位置层级、主机名建筑代码)属于标识符,应予替换。

还需涵盖嵌套和复合标识符(见下文)。

请在处理过程中应用占位符约定和格式规则(见下文)。

嵌套和复合标识符

这些内容很容易被遗漏。请将它们纳入映射,包括嵌套在 URL、复合 ID 和路径片段中的令牌。

十六进制复合 ID 中隐藏的 IPv4。 某些供应商 ID 的格式类似 {0x00000001,0x1,0xcb007114,0x00000002}。一个十六进制双字可能是 IPv4 地址(请尝试两种字节序)。如果替换了 origin / src / dst IP,请将每个双字解码为 IPv4。如果任一种解码结果是合理的公网或私网 IP,且与已替换的 origin 不匹配,则将该双字替换为你为 origin 使用的同一个文档专用 IP 的十六进制编码(保留 0x + 8 位十六进制数字)。保留外层 {0x…,0x…} 结构;只更改承载 IP 的双字。示例:0xcb007114 → 203.0.113.20(大端序);如果 origin 已替换为 198.51.100.10,则使用 0xc633640a。

拓扑编码的主机名。 这不是 DNS 名称:SW-BLDG-01、CHI-FW-01、DC1-VPN-MGMT。在主机名 / syslog 主机 / 设备名称字段中,替换站点 / 角色 / 建筑代码。不要替换 %NAME-6-302018 这样的供应商 syslog 消息 ID——它们是产品助记符,不是主机名。占位符:host-1.example.local 或 example-fw-01,长度类别与原文匹配(短令牌与 FQDN)。

策略 / ACL / access-group 名称。 在策略、ACL 或 access-group 值中,将 \d{8,14} 日期样式的数字串替换为 20240101000000(数字长度相同);将 vs\d+ 替换为 vs01(或删除 vs / 日期后缀:example-policy);名称中的 VLAN 编号替换为 vlan100。保留令牌类别(仍应看起来像策略名称)。示例:vlan200-20240115103000 → vlan100-20240101000000。

接口名称。 将 ethN-MM.VLAN 替换为 eth1-01.100(保留 eth + 带点的子单元结构)。将 IF-<org>-… / 位置词替换为 IF-Example(如果存在 IF- 前缀,则保留)。如果 inside / outside / lan / wan 是接口角色而不是站点名称,则可以保留。如果令牌代表客户站点或组织,优先替换。

包含组织单位的 Windows / SMB 路径。 将最后两级目录之前的目录组件替换为通用片段(example-department、E01、EXAMPLE-UNIT)。保留层级、反斜杠以及最终文件名(如果 Thumbs.db 是通用操作系统文件)。像 \2026\ 这样的年份文件夹可以保留(不具识别性)。

保留前缀的不透明 ID。 SaaS 和身份平台 ID 通常由短类型前缀和长混合大小写后缀组成。替换后缀,保留前缀。同一原值 → 同一占位符。也要将 URL 路径中的 base64 数据块替换为长度相同的合成 base64。将看起来真实的应用 / 角色显示名称替换为通用名称(Example Application Role Management)。

设备序列号和 MDM ID。 将 device_id / serial / DeviceId(及类似字段)中的长十六进制 / 字母数字值替换为字符集和长度相同的合成值(SN000000000001、SEC123ABCDEFG45H)。不要保留真实设备或 MDM 序列号。

身份存储名称和组层级。 将 <NAME>-AD / 身份存储替换为 EXAMPLE-AD。对于以井号分隔的层级,保留 Location#All Locations# / Device Type#All Device Types# 等结构性前缀;如果叶节点是真实城市 / 站点,则替换叶节点(Example-Site)。即使用户名已脱敏,看起来真实的存储名称仍必须替换。

URL 和查询字符串中嵌套的 IP。 替换顶层 src_ip / dst_ip 后,扫描 URL 查询和路径中的 ip=、src=、dst= 以及点分十进制四段式 IP 地址。如果该主机在其他位置出现过 RFC 5737 IP,则使用同一个 IP;否则使用 198.51.100.10。即使周围的 URL 格式错误,也要执行此操作。

OCSP / AIA / CRL 证书路径。 http://ocsp.digicert.com/AAAAAAAAAAAAAAAAAAAAAAAAAAAA——主机可以保留(公共 CA),路径包含证书序列号 / 颁发者材料。如果主机名匹配 ocsp. / crl. / cacerts.(无论是否为公共主机),请将路径替换为长度相同的合成 base64 / 十六进制字符串(全零或 A)。保留 / 数量和字符集类别。 用户名中的 JNDI / 插值探测。 如果某个字段包含 ${jndi:、${lower: 或 ${::-,请将整个字段值替换为合成用户名(alice.johnson;如果需要保留原始引号或撇号,则使用 Lab1's User)。不要保留探测 URL。保留周围的引号。

客户遥测中的公共目标主机名。 如果公共主机(docs.google.com、api.github.com)是日志源供应商 API,则可以保留。在防火墙、代理、DNS、UTM 和内容过滤事件中,目标主机名和目标 IP 属于客户遥测。即使它们是知名消费类网站(youtube.com)或公共单播 IP,也要替换。保留作为日志源供应商 API 的产品主机(GitHub 审计日志中的 api.github.com)。

步骤 2 — 验证结构完整

清理后确认:

  • 行数不变;不要丢弃末尾的 KV 对
  • 输出长度必须**≥输入长度的 70%,除非唯一改动是将长令牌替换为形状相同的占位符(缩短查询参数后,2k URL 可以变短,但不要删除其余 syslog 行**)。如果你需要删除重复字段来“完成”匿名化,那就做错了——请改用两遍映射法
  • 再次扫描残留项:URL 中的 ip= / src= / dst= / 点分四段 IP、复合 ID 中的十六进制 dword、类似主机名的拓扑令牌、设备序列号、保留前缀结构的不透明 ID
  • JSON 行仍然是有效 JSON(适用于 NDJSON 文件):
    python3 -c "
    import json, sys
    with open('FILE') as f:
        for i, line in enumerate(f, 1):
            line = line.strip()
            if line:
                try: json.loads(line)
                except Exception as e: print(f'Line {i}: {e}')
    "
    
  • 时间戳仍符合原始格式(包括时区缩写——见“保留内容”)
  • 解析器或条件分支所依赖的枚举值 / 状态值 / 操作值保持不变

占位符规范

使用一致、逼真的替换值,不要使用会导致格式敏感型解析器出错的 REDACTED 字符串。

类型替换值
电子邮箱[email protected]、[email protected]
IPv4RFC 5737 地址段:198.51.100.10、203.0.113.20、192.0.2.30
IPv62001:db8::10
主机名 / FQDNhost-1.example.local、srv-web-01.example.internal
拓扑主机名host-1.example.local
域名example.com、example.org、example.net
UUID89a1d5c1-2b3e-4f67-8a9b-0c1d2e3f4a5b
API 密钥 / 令牌sk_test_example_key_1234567890、dGVzdC10b2tlbi0xMjM0NTY3ODk=
用户名alice.johnson、bob.smith
显示名称Alice Johnson、Bob Smith
组织 / 公司名称Example Corp、Acme Inc
账户 / 租户 ID000000000000、example-tenant-id
云资源 IDarn:aws:iam::000000000000:user/example-user
S3 存储桶名称example-bucket
MAC 地址00-00-5E-00-53-23(RFC 7042 文档范围)
序列号SN000000000001
设备 / 机器 ID使用合成 UUID 或 device-id-example-000001
MDM / 供应商前缀设备 ID字符集和长度保持一致(SEC123ABCDEFG45H)
Windows SIDS-1-5-21-000000000-000000000-000000000-1000
文件路径(Windows)C:\Users\example-user\AppData\...
文件路径(Unix)/home/example-user/... 或使用 ~
Kubernetes 集群example-cluster、example-node-1
电话号码734-555-0100(555 号段保留用于虚构号码)
数据库主机 / 名称db-host.example.local、example_database
部门 / 组织单位example-department、/example-org/example-unit
哈希 / 部分令牌替换为格式相同的完整合成令牌
DHCP 指纹example-dhcp-fingerprint-000001
JA4 指纹替换为长度相同的十六进制字符串
事务 / 序列 / 事件实例 ID(数字)使用与原数字位数相同的合成整数,例如:48273915 → 10000002
会话 / 请求 / 关联 ID使用长度相同的合成字符串(保留长度和字符集),不要使用描述性名称
复合 ID 中的十六进制 dword8 位十六进制数字,带 0x 前缀;编码与 origin / src 相同的 RFC 5737 IP
带日期的策略 / ACLexample-policy、vlan100-20240101000000
接口 ethN-MM.VLANeth1-01.100
带类型前缀的不透明 ID保留前缀,使用合成后缀
身份存储EXAMPLE-AD
位置层级末级Example-Site
OCSP / CRL / AIA 路径使用长度相同的 A / 0 base64 字符串
JNDI 用户名alice.johnson(保留引号)

一致性规则:在整个文件中,将相同的原始值映射为相同的占位符。如果同一个 IP 出现 10 次,这 10 处都必须替换为同一个 IP,以便仍可测试跨事件关联。先构建完整映射,再全局应用。不同的原始值必须使用不同的占位符,不要把 30 个用户名都替换成 alice.johnson。嵌套副本(同一个 IP 出现在 src、URL 中的 ip= 以及十六进制复合 ID 中)都必须使用该原始 IP 对应的占位符。

形状规则 — 替换内容必须与原始值格式一致

每个替换值都必须与原始值的形状一致。解析器和下游处理依赖的是值的格式,而不只是字段是否存在。

  • 数字 ID → 数字 ID:/d/123/edit → /d/456/edit,而不是 /d/example-document-id/edit
  • 事务 / 序列 / 事件实例 ID → 相同形状的数字:如果该值是事件级跟踪标识符,请对其进行掩码处理并保留位数。例如,CEF cn1=48273915 cn2=3061847 → cn1=10000002 cn2=1000002
  • UUID → UUID:真实 UUID 必须替换为相同版本的合成 UUID,而不是描述性字符串
  • URL → URL:只替换敏感部分(主机名、路径 ID、嵌套的 ip= / src= / dst=)——保留协议、路径结构、查询字符串形状,以及任何非法字符
    • https://docs.google.com/drawings/d/123/edit → https://docs.google.com/drawings/d/000000000000/edit(替换 ID,而不是主机名——docs.google.com 是公共服务名称,不是组织标识符;这适用于供应商 API日志)
    • https://internal.corp.com/api/v1/resource → https://host-redacted.example.local/api/v1/resource(替换内部主机名,保留路径)
    • 在防火墙 / 代理 / UTM 遥测数据中,还要替换目标主机和 IP(参见“应保留的内容”)。不要将格式错误的 URL 改写为 https://example.com/path 或 /some/api
  • 字符串 ID → 相同长度或相同格式的字符串:不透明的字母数字 ID 应替换为长度相近的不透明字母数字占位符,而不是描述性名称
  • URL 中的主机名与独立主机名:仅替换标识真实内部基础设施的主机名,或防火墙 / 代理 / UTM 日志中客户访问的目标主机名。在 SaaS / 供应商 API 日志中,公开且广为人知的主机名(docs.google.com、api.github.com、s3.amazonaws.com)标识的是服务,而非组织,无需替换

不得替换格式错误或无效值。 如果某个值看起来损坏、为合成值,或不包含真实身份信息(例如 http://1=Y +z\\、00/00/0000、N/A、空字符串、看起来像占位符的值),请原样保留。将格式错误的值替换为格式正确的占位符会改变其形状。你仍可以替换格式错误的令牌中嵌入的身份信息(真实 IP、主机名、用户),但必须保留其格式错误特征——额外的引号、未编码的 { }、URL 中的空格、截断字段、U+FFFD。

如果不确定应采用何种形状,请查看同一文件中相同字段类型的相邻值,并匹配其格式。

应保留的内容

请勿替换:

  • 协议名称、动作动词、事件类型、严重级别(ALLOW、DENY、INFO、ERROR)
  • 产品定义的事件代码/类型 ID,例如 Windows 事件 ID——这些描述的是事件语义,而非特定客户的事件实例
  • 供应商的 syslog 消息 ID(%NAME-6-302018)——这是产品助记符,不是主机名
  • HTTP 状态码、端口号、数值指标(计数、大小、时长)
  • 字段名称和键
  • 时间戳(格式和时区必须保持不变)。请勿更改时区缩写、纪元值或时钟字段:
    • 请勿将 Jun 27 14:06:33.189 JST 改为 Jul 24 00:47:24.618 CET
    • 请勿偏移或以其他方式更改纪元/Unix 时间戳,即使只改动少量时间。数字时钟字段(eventtime、纪元毫秒数及类似字段)必须逐字节保持不变。
    • 请勿将 JST、EDT、EST、Eastern、(GMT-3:00)Buenos Aires, Georgetown 替换为其他时区。日期解析器依赖这些缩写;将 JST 换成 CET 不仅会导致解析失败,还会编码出一个地理位置(而且是错误的位置)。时区缩写的隐私保护不在此范围内——请原样保留
  • 结构性标记(方括号、花括号、竖线、逗号、制表符)
  • URL 中公开且广为人知的服务主机名(docs.google.com、api.github.com 等),前提是它们是日志来源供应商 API——如果路径 ID 涉及敏感信息,请替换路径 ID,而不是主机名。 在防火墙、代理、DNS、UTM 和内容过滤事件中,目标主机名和目标 IP 属于客户遥测数据。即使它们是广为人知的消费者网站(youtube.com)或公共单播 IP,也请替换。保留作为日志来源供应商 API 的产品主机名(例如 GitHub 审计日志中的 api.github.com)。
  • 文件哈希(文件内容的 MD5、SHA1、SHA256)——这些哈希可用于内容寻址,安全;请勿替换
  • 用户代理字符串(Mozilla/5.0 ...)——它们会透露浏览器/操作系统类型,但不会透露身份;可以保留
  • 地理位置增强字段中的城市和国家名称——仅替换精确坐标和街道地址
  • Syslog PRI/RFC5424 标头——请勿添加、删除或改写它们

评论

支持 Markdown