把一段日志、一份名单、一张工单记录发给外部同事或贴进工单系统之前,总要处理一遍。处理方式选错的后果分两种:处理不够,隐私泄露;处理过头,数据废掉——比如把订单号当成银行卡打了码,对方拿着这份数据没法排查问题。
这篇讲清楚三件事的边界:什么时候打码,什么时候加密,什么时候干脆别用真数据。三个工具都在浏览器本地运行,原始文本不上传服务器。
一、先校验再打码:不然会打错东西
纯靠正则找敏感信息的准确率很低,因为长数字到处都是。一条 订单编号 20260902000123456789 里的数字串长度落在银行卡的位数区间内,纯正则会直接把它打成 ****。日志里的时间戳、流水号、设备号同理。
敏感信息批量脱敏的做法是正则只负责找候选,能不能算命中由校验决定:
- 银行卡号:匹配 16 到 19 位数字(允许用空格或短横线分组),然后做 Luhn 校验。Luhn 是发卡组织通用的校验位算法,从末位起隔位加倍再求和取模 10。随机一串数字通过 Luhn 的概率约十分之一,加上这道校验,误判量下降一个数量级。
- 身份证号:18 位的先验证出生日期段是否是合法日期(月份 01 到 12、日期不越界),再算 ISO 7064 MOD 11-2 校验位,最后一位不对就不算命中。15 位旧版也能识别。这两道校验叠加,把随机数字串误判成身份证的概率压得很低。
- 手机号:11 位、以 1 开头、第二位 3 到 9,并且要求前后不是其他数字。这个「前后不是数字」的边界约束很关键,否则一个 20 位的流水号里随便截出 11 位就会命中。
- IP 地址:每段必须在 0 到 255 范围内,否则
192.168.1.999这种也会被当成 IP。 - 固定电话:区号 3 到 4 位加 7 到 8 位号码,且号码首位不为 0 或 1。
所以工具给出的命中数量统计要当成核对工具用,不是装饰。粘进去先看每类命中几条,和你预期的条数对不上,就说明规则勾多了或者数据格式特殊,这时该调整而不是直接复制结果。高亮预览同样是为核对准备的:被修改的位置会标出来,扫一眼就知道有没有误伤。
反过来也要接受一个事实:规则匹配做不到百分之百。格式异常的数据会漏(比如手机号中间被人手动加了括号)、伪装成正常文本的敏感信息会漏。批量脱敏解决的是「一份几百行的数据里绝大部分敏感字段」,最后一遍人眼扫一遍是省不掉的。
二、多条规则命中同一段文字时怎么裁决
一段 18 位身份证号,前 11 位有可能同时满足手机号的形状;一串带短横线的长数字,可能既像银行卡又像固定电话。命中区间重叠时必须有裁决规则,否则替换会互相踩踏,产出乱码。
工具的裁决顺序是:先按起始位置排序,位置相同时优先级高的赢,优先级相同时匹配更长的赢,然后从左到右取一组互不重叠的命中。优先级是按「规则有多严格、误判后代价有多大」定的:
- 自定义关键词最高。这是你手工指定的词,语义最明确,必须让它压过所有内置规则。
- 身份证号最高优先级的内置规则。它有两道校验,误判概率最低,而且身份证号泄露的代价最大。
- 邮箱、车牌次之,格式特征明显。
- 手机号、固定电话、IP 地址再次之。
- 银行卡号优先级压得较低,原因正是它的正则最宽松——允许空格与短横线分组,形状上和别的数字串重合度高,所以让更严格的规则先判。
- 详细地址最低。地址正则是「省市区 + 门牌」的模糊匹配,可能覆盖很长一段中文,优先级高了会吞掉里面的其他命中。
理解这个顺序的实际价值是:当你发现某个字段没被打码,往往不是规则没写,而是被另一条优先级更高、区间更长的规则吃掉了。这时先取消勾选那条抢赢的规则,单独跑一遍,就能确认到底是谁命中的。
三、打码方式按用途选
工具提供五种遮蔽方式,选择依据是「对方还需要用这个字段干什么」:
- 保留首尾(默认):
138****5678这种。可读性最好,适合内部沟通与工单描述,缺点是保留的信息最多。 - 仅保留后四位:对账、客服核身的行业惯例。用户报后四位、你比后四位,不需要完整号码。
- 仅保留前三位:只想保留号段或地区特征(判断运营商、判断发卡行)时用。
- 全部遮蔽:完全不需要原值,只需要知道这里原来有个东西。
- 替换为类型标记:直接换成
[手机号]、[身份证号]这样的标记。给外部看的文档首选这一种,因为它连长度信息都不泄露,而且读起来最清楚——对方一眼知道这里是什么字段。
两个字段有特殊处理:邮箱只遮用户名、保留域名(****@example.com),因为域名往往是识别来源的关键,而且不构成个人身份;地址只遮门牌部分,省市区保留,因为区县级信息通常是分析需要的粒度。选「全部遮蔽」时这两条特殊处理会让位给全遮。
还有个容易被忽略的风险:单字段打码不等于匿名。把手机号打了码,但同一行还留着姓名、公司、职位、精确到室的地址,把这些拼起来照样能定位到人。对外披露时的正确心态是「先删列,再打码」——不需要的字段整列删掉,比逐个打码更彻底。
四、脱敏与加密:一个不可逆,一个可逆
这两件事经常被混着说,但它们的用途完全相反。
脱敏是不可逆的。信息被丢弃了,138****5678 中间那四位在结果里不存在,谁都还原不了,包括你自己。所以脱敏适用于「对方永远不需要看到原值」的场景:贴公开工单、写文档、做演示、给第三方做统计分析。
加密是可逆的。文本口令加密解密用浏览器原生的 Web Crypto 做 AES-GCM 256 位加密,密钥由口令经 PBKDF2-HMAC-SHA256 迭代 25 万次派生,每次加密都随机生成盐值与初始向量。几个设计点值得知道:
- 高迭代次数是为了抗暴力破解。口令熵本身不高,25 万次迭代让攻击者每试一个口令都要付出同样的计算代价。
- 随机盐让相同明文加两次得到完全不同的密文,同时使预计算的字典表失效。
- AES-GCM 自带认证标签,密文被改过一个字符,或者口令输错,都会明确报错,而不是吐出一段错误明文——这一点比传统的 CBC 模式重要得多,避免了「解出来像是对的但其实错了」。
- 输出是 Base64 并按行折行,可以直接贴进聊天消息、邮件、笔记,不会被换行破坏。
- 口令忘了就真的没了,没有找回通道。这是设计使然,不是缺陷。
选择的判断标准只有一句:对方需不需要看到原值。需要就加密,口令走另一条通道给(比如内容发邮件、口令打电话说);不需要就脱敏。两个反例都很常见——把打码当加密(以为 138****5678 是安全的,实际上配合其他字段可以反推)、把密文当脱敏结果发给外部(密文是可逆的,风险只是转移到口令上,不是消除了)。
五、测试环境:造假数据比脱敏真数据更安全
给测试环境准备数据时,很多团队的做法是「把生产库导一份,脱敏后灌进去」。这条路有三个实际问题:
- 脱敏数据仍是真实数据的衍生物。脱敏强度不够、字段组合起来仍可重识别,测试库的安全等级又通常比生产低,这是很常见的泄露路径。
- 打码会破坏格式,反而测不出问题。
138****5678过不了前端的手机号校验,****开头的身份证算不出校验位,接口层的校验逻辑全部会被这批数据挡在门外——你测的其实是「校验能不能拦住脏数据」,而不是业务流程。 - 覆盖不到边界值。生产数据的分布是自然分布,缺少你想测的极端情况。
测试数据生成器是另一条路:直接造一批格式完全合法但不对应任何真人的数据。它的关键特性是行内自洽:
- 姓名用字与性别匹配;
- 身份证号的出生日期段与出生日期字段一致,顺序码奇偶与性别一致,校验位按 ISO 7064 MOD 11-2 正确计算;
- 地址与身份证前六位归属同一区县;
- 银行卡号能通过 Luhn 校验;
- 手机号使用运营商在用号段。
这一串「自洽」直接决定了它能不能用:如果身份证的性别位和性别字段对不上,你的业务校验就会报错,这批数据一条都用不了。可选字段覆盖姓名、性别、年龄、出生日期、身份证、手机号、邮箱、地址、公司、职位、银行卡、开户行、车牌、用户名、IP 与注册时间,能设置条数、性别分布与年龄区间。
有一个功能对排查问题特别有用:填入固定随机种子可以重复得到同一批数据。测试用例里记下种子,任何人任何时候都能重现出一模一样的数据集,比把一个 CSV 文件传来传去可靠。导出格式有制表符表格、CSV、JSON 和 SQL INSERT,最后一种可以直接灌库。
落地建议:新功能的测试数据一律用生成器造;只有在复现线上特定 bug 时才动生产数据,并且只取必要的那几行、脱敏后用完即删。
常见问题
为什么我的订单号也被打码了? 说明它恰好通过了银行卡的 Luhn 校验或落在其他规则的形状里。取消勾选银行卡号那条规则重跑一遍,或者改用「替换为类型标记」并核对高亮位置,就能确认是哪条规则命中的。
脱敏后的结果能还原回原文吗? 不能,也不应该能。需要对方能看到原值的场景请用口令加密,密文和口令分开两条通道传递。
加密后的密文能直接贴在群里吗? 密文本身贴出来没问题,它是 Base64 文本且带完整性校验。风险全在口令上:不要在同一个群里发口令,也不要用生日、公司名这类能猜到的口令,工具提供口令强度评估和随机强口令生成,用它生成的口令再存进密码管理器。
生成的身份证号和银行卡号会撞到真人吗? 号码是按规则随机拼装的,格式合法所以理论上存在与真实号码重合的可能,但它不对应任何真实开户信息或账户,也不携带任何真实个人数据。用途限定在接口联调与表单校验,不要拿去做任何实名或支付相关的尝试。