敏感数据识别是数据安全治理的基础环节。无论是做数据脱敏、访问控制还是合规审计,都必须先知道哪些数据属于敏感数据、分布在哪些字段或文件中。很多团队在落地时容易把敏感数据识别等同于写几条正则表达式,实际上单纯的正则匹配会产生大量误报,也难以覆盖上下文相关、跨列关联等复杂场景。更合理的做法是把规则匹配、字典对照、命名实体识别和分类分级结合起来,形成一套可解释、可调整的识别流程。

一、敏感数据识别的主要技术路径
敏感数据识别通常分为规则匹配、字典匹配、模型识别和混合策略四类。规则匹配借助正则表达式或模式模板来识别身份证号、手机号、银行卡号等具有固定格式的数据。例如中国大陆居民身份证号为18位,前17位是数字,最后一位可以是数字或X,对应的正则模式可以写成 \d{17}[\dXx]。这种方式的优点是实现简单、执行速度快,缺点是只能覆盖格式固定的数据,遇到地址、姓名、公司名称等没有固定格式的敏感字段就无能为力。
字典匹配主要用于识别非结构化文本中的专有名词或特定标识,比如客户姓名、项目代号、内部系统名称等。企业可以维护一份敏感词字典,将司法、医疗、财务等领域的专用名词纳入其中。字典匹配的准确率依赖字典质量,漏报率较高,但可以补充正则无法覆盖的场景。命名实体识别和机器学习模型则更适合从自然语言中提取人名、地名、机构名,以及通过上下文判断某些字段是否敏感。模型方法通常需要标注语料和持续调优,落地成本较高,适合在规则匹配之后作为二次识别层。
实际工程中很少只用单一方法。例如在数据库字段扫描时,可以先根据字段名和注释做初步判断,再对字段值抽样执行正则匹配,最后结合数据分类分级规则确认敏感级别。这样既能控制扫描耗时,又能显著降低误报率。
二、分类分级是识别结果落地的关键
识别出敏感数据之后,如果不能给出合理的分类和分级,后续的安全策略仍然无法执行。敏感数据分类通常依据业务属性,例如个人身份信息、金融信息、医疗健康信息、企业商业秘密等。分级则依据数据泄露后的影响程度,例如公开数据、内部数据、秘密数据、机密数据。国家标准和行业规范会给出基础框架,企业需要结合自身业务进一步细化。
一种常见的做法是建立字段级分类分级表。比如将身份证号归入个人身份信息,默认级别为高;将手机号归入个人联系方式,级别为中;将登录日志中的IP地址归入运行监控信息,级别为低。识别引擎在完成匹配后,可以按照这张表自动为字段打上分类和级别标签。这样后续脱敏系统可以根据级别决定是否加密、替换或截断,审计系统也可以只关注高敏感级别的数据流向。
需要注意的是,同一个字段在不同业务表中的敏感级别可能不同。比如姓名在客户主表中是高敏感,在员工花名册中可能只是内部数据。因此分类分级不能只看字段名,还要参考表用途、字段组合以及访问场景。更完善的实现可以引入数据地图,记录字段的血缘关系和上下文语义,帮助识别引擎做出更准确的判断。
三、用Python实现一个可运行的敏感数据扫描器
下面通过一个Python脚本展示如何从文本中提取身份证号、手机号和银行卡号。脚本使用正则表达式做基础匹配,并加入简单的上下文排除逻辑,避免把订单号或日期误判为身份证号。代码中保留了校验位函数的扩展位置,实际项目可以接入更严格的校验算法。
import re
# 常见敏感数据模式
PATTERNS = {
"身份证号": r"\b\d{17}[\dXx]\b",
"手机号": r"\b1[3-9]\d{9}\b",
"银行卡号": r"\b\d{16,19}\b"
}
def scan_text(text):
results = []
for name, pattern in PATTERNS.items():
for match in re.finditer(pattern, text):
value = match.group()
# 上下文排除:避免纯数字序号被当作银行卡
if name == "银行卡号" and len(set(value)) < 4:
continue
results.append((name, value, match.start()))
return results
sample = "用户13800138000的身份证号是11010519491231002X,银行卡号是6222020200112233445。"
for item in scan_text(sample):
print(item)
上述代码中的 \b 表示单词边界,可以避免在一个更长的数字序列中截取到子串。身份证号的正则模式 \d{17}[\dXx] 已经覆盖了最后一位为X的情况,但未校验身份证号的校验位。如果需要降低误报,可以在匹配后加入GB 11643标准中的加权因子计算,把不符合校验位的数字排除。
银行卡号的识别要特别小心。16到19位数字可能出现在订单号、流水号、时间戳等场景中。示例里用了一个简单判断,当数字串中不同字符少于4个时跳过,这能过滤掉部分重复数字的测试数据,但更可靠的做法是接入Luhn算法校验。Luhn算法可以校验银行卡号和部分信用卡号的有效性,能大幅减少误报。手机号相对容易识别,但也可能被版本号、序列号干扰,所以扫描时需要结合字段所在位置和上下文。
四、避免常见误区和优化扫描性能
敏感数据识别的最大误区是把识别结果直接当作最终结论。正则匹配只能说明数据格式相似,并不能证明数据真实存在。比如一个18位数字可能只是订单流水号,而不是身份证号。为了控制误报,必须引入校验位验证、上下文关键词和字段类型约束。上下文关键词可以包括姓名、身份证、银行卡等词,如果这些词出现在匹配值附近,则提高置信度;如果附近全是订单、流水、日期等词,则降低置信度或排除。
另一个常见问题是扫描性能。面对数亿行数据或大量文本文件时,如果逐条执行复杂的正则和模型推理,耗时会非常可观。优化思路包括:先使用轻量级预筛规则找出疑似字段,再对疑似数据执行精确校验;对结构化数据只扫描字段元信息和抽样值,而不是全量扫描;对非结构化文件可以先抽取文本,再做批量匹配。正则表达式本身也需要优化,避免使用灾难性回溯的模式,例如 (a+)+ 这类嵌套量词。
此外,识别结果需要定期更新。业务系统不断变化,新的敏感字段类型会出现,旧的正则规则可能失效。企业应建立规则版本管理和误报反馈机制,让安全、业务和开发人员都能对识别结果进行标记。通过持续积累标注样本,后续可以逐步引入机器学习和规则引擎混合策略,提升对姓名、地址、医疗描述等非固定格式敏感信息的覆盖能力。