敏感数据识别与分类:PII、PHI、PCI 与企业自定义分类
数据列遮蔽的第一步,不是写代码,而是搞清楚:你到底要保护什么?
我见过不少团队,上来就对着数据库一顿操作,把身份证号、手机号全遮了。结果业务方找上门来——「你把我们的分析字段也遮了,这活儿没法干了。」说白了,遮蔽之前,你得先做分类。哪些是红线数据,哪些是黄线数据,哪些压根不用管。
这一章,我们就来聊聊敏感数据的识别与分类。我会结合我自己的项目经验,把 PII、PHI、PCI 以及企业自定义分类这四块讲透。
2.1 个人身份信息(PII)识别
PII 是最常见的敏感数据。任何能直接或间接识别到具体个人的信息,都算 PII。
直接标识符:姓名、身份证号、社保号、护照号、生物特征(指纹、人脸)。
准标识符:出生日期、性别、邮编、职位。单个看没啥,组合起来就能锁定一个人。
核心原则:判断一条数据是不是 PII,别只看字段名。要看它能不能「关联回个人」。我在项目中遇到过,有人把「员工编号」当普通字段放出去了,结果这个编号就是身份证号的后六位——直接泄露。
实际工作中,我习惯用正则表达式做初步扫描。比如身份证号(中国大陆 18 位):
import re
# 中国大陆身份证号(18位,最后一位可能是X)
pii_id_pattern = r'\b[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]\b'
# 手机号(中国大陆)
pii_phone_pattern = r'\b1[3-9]\d{9}\b'
def scan_pii(text):
ids = re.findall(pii_id_pattern, text)
phones = re.findall(pii_phone_pattern, text)
return {'id_cards': ids, 'phones': phones}
避坑指南:我曾经用正则扫全量数据,结果把「123456789012345678」这种测试数据也当身份证号抓出来了。后来我加了校验位算法,误报率才降下来。正则只是第一步,别忘了加业务规则过滤。
2.2 受保护健康信息(PHI)识别
PHI 是医疗行业的红线。HIPAA(美国健康保险携带和责任法案)定义了 18 类 PHI 标识符。国内虽然没有 HIPAA,但《个人信息保护法》对健康数据的要求同样严格。
常见的 PHI 字段包括:
- 病历号、诊断编码(ICD-10)
- 检查报告、化验结果
- 保险信息、医保卡号
- 治疗记录、处方信息
PHI 的识别难点在于:它经常藏在非结构化文本里。比如医生的诊断记录:「患者主诉头痛,既往有高血压病史,服用硝苯地平。」这里面「高血压病史」就是 PHI。
我建议的做法是:先用关键词匹配(比如「病史」「诊断」「处方」),再用 NER(命名实体识别)模型做二次确认。别指望一步到位。
# 简单的 PHI 关键词扫描
phi_keywords = ['病史', '诊断', '处方', '住院号', '医保卡', 'ICD-10']
def scan_phi(text):
found = []
for kw in phi_keywords:
if kw in text:
found.append(kw)
return found
注意:PHI 的遮蔽不能影响临床诊疗。我见过一个案例,把病历里的「高血压」三个字遮了,医生开药时看不到既往病史,差点出医疗事故。遮蔽策略一定要和业务方对齐。
2.3 支付卡行业数据(PCI)识别
PCI DSS(支付卡行业数据安全标准)对信用卡数据的保护要求极其严格。核心数据包括:
- 主账号(PAN):卡号本身
- 持卡人姓名
- 有效期
- 服务代码 / CVV
其中,CVV 和磁条数据是禁止存储的。你想想看,如果数据库里存了 CVV,一旦泄露,持卡人可以直接被盗刷。PCI DSS 明确要求:交易完成后,必须丢弃 CVV。
卡号的识别相对简单,Luhn 算法可以校验卡号合法性:
def luhn_check(card_num):
# 去掉空格和横线
digits = [int(d) for d in card_num if d.isdigit()]
# 从右向左,每隔一位乘2
for i in range(len(digits)-2, -1, -2):
digits[i] *= 2
if digits[i] > 9:
digits[i] -= 9
return sum(digits) % 10 == 0
# 测试
print(luhn_check('4111111111111111')) # True (Visa测试卡号)
print(luhn_check('1234567890123456')) # False
个人经验:我在做支付系统审计时发现,很多开发人员把卡号明文写进了日志。排查时,我写了个脚本扫描所有日志文件,用 Luhn 算法过滤出疑似卡号,结果抓出来 200 多条。后来我们强制在日志框架层做了脱敏。
2.4 企业自定义敏感数据分类
除了通用的 PII、PHI、PCI,每个企业都有自己的「家规」。比如:
- 金融行业:交易流水、风控模型参数、客户资产信息
- 电商:用户浏览行为、购物车数据、优惠券码
- 制造业:供应商名单、成本报价、设计图纸
- 互联网:、内部 、数据库连接串
我建议的做法是:建立一张敏感数据分类矩阵表,由数据治理委员会统一维护。
| 分类 | 示例字段 | 敏感等级 | 遮蔽策略 |
|---|---|---|---|
| PII | 身份证号、手机号 | 高 | 动态遮蔽(保留后4位) |
| PHI | 诊断记录、病历号 | 极高 | 完全遮蔽或泛化 |
| PCI | 卡号、CVV | 极高 | CVV禁止存储,卡号遮蔽 |
| 企业自定义 | 、内部 | 高 | 替换或加密存储 |
嗯,这里要注意:分类不是一成不变的。业务变了,数据用途变了,分类也要跟着调整。我每半年会做一次分类复审,拉着业务、法务、安全三方一起过。
2.5 敏感数据分类整体流程
说了这么多,我把整个识别与分类的流程画了张图,方便你理解。
这张图的核心逻辑是:先扫数据源,用正则和关键词做初步匹配,然后根据匹配结果判断属于哪一类敏感数据,最后按敏感等级制定遮蔽策略。每一步都需要人工复核,别全自动化——机器会漏,也会误报。
一个小技巧:我习惯在分类矩阵里加一列「业务影响评估」。比如遮蔽身份证号,对财务报税有影响;遮蔽手机号,对营销推送有影响。提前评估,省得后面扯皮。