最近几个月,我都在做一件事情,就是牵头制定公司数据安全相关的各种规章制度和技术细节。而涉及到数据访问,去做数据脱敏就是一个无法回避的事情,尤其是金融行业,各种高敏感的客户资料、交易信息等等。不同的数据类别不同的安全要求,衍生出的脱敏方式也不尽相同。
脱敏的目的
一句话,不该看的别看。但是如果我仅仅只说这一句,那恐怕是不足以撑起这篇文章的,仍然还是要仔细讲述一下每个数据脱敏的目的。
a)满足监管要求
金融监管对于数据安全以及隐私的保护非常细致,小到一个具体的属性,大到一个门类,都有明确的安全要求以及备份要求。这也督促了所有从业者要严格执行,甚至有时候要比监管的要求再严一些。做过生产运维的朋友可能都有过类似的经验,比如我们给业务部门的SLA是1小时,那么内部要求就会更短,比如30分钟甚至更短。
b)保护客户隐私
实际上即便没有监管要求的行业,客户的隐私也都是有法律义务去保护的。而客户隐私怎么界定,哪个属性是隐私,哪个不是,不同行业不同公司,又有不同的理解,比如有的觉得客户姓名不算高敏感,有的会觉得客户姓名就是高敏感。
c)支持开发测试
生成出来的测试数据,看上去再合理,也是生成的,和实际生产的数据仍然有着本质区别,有时候需要对开发测试要更精准的场景时,那么从生产环境导入数据,就成为了最合适的选项。而生产和测试的权限控制不可能做到一模一样,那么脱敏就是必须的。
d)促进数据共享
很多时候,数据需要在不同团队或者部门之间流转,比如风控部门要看看交易部门的交易流水,通过模型去提前判断并预警风险,合规部门需要对客户资料做审核,不是数据拥有者部门是不可以看到所有数据的,但是数据共享又是业务继续的硬性要求,只有做数据脱敏。
当然,我也没有列全,还有一些场景可能也会用到,比如向监管汇报或者给客户展示部分数据的场景,都是客观存在的。”不该看的别看“既是在保护数据,也是在保护客户和业务部门,甚至在某种意义上,也是在保护看数据的人。
常用的脱敏方式
回到脱敏方式上,我们以数据库作为例子,日常会有哪些脱敏的办法。
1. 数据无效化(data invalidity)
第一次听到这个词还是在外企的时候,简而言之就是,通过特定的方式,让数据库里的数据不再具有有效性,举个例子:
user_id | user_name | mobile | role | comment |
---|---|---|---|---|
1 | Abby | 130****1234 | Sales | |
2 | Bob | 131****5678 | Manager | |
3 | Charlie | 135****6789 | Engineer | |
4 | Dora | 136****4321 | Other |
在这个表里,敏感数据是手机号,但是通过技术手段,可以是用对称加密方式,也可以直接将中间四位替换成****,直接把原有的格式破坏了,这些数据也就都成了无效数据。简单粗暴,但是会破坏数据格式有可能需要做类型转换,比如有的系统手机号是以bigint存,这时候就要改成varchar或者text。
2. 全量替换
对于某些敏感信息,我们可以选择全部替换成一个特定的值,这样原有的值也在这个库里再没有办法获取,例如:
user_id | user_name | mobile | role | comment |
---|---|---|---|---|
1 | Abby | 1300000000 | Sales | |
2 | Bob | 1300000000 | Manager | |
3 | Charlie | 1300000000 | Engineer | |
4 | Dora | 1300000000 | Other |
手机号全部替换成了1300000000。但是这样丧失了数据的多样性,比如我把所有客户表的生日都替换成2000-01-01,代价就是这个数据副本无法统计客户的年龄分布,能够应对的业务开发场景就被人为缩小。
3. 打散分布
针对第二个方式,假如我就是需要年龄分布,或者要统计某个客户的总消费额,但是又不能让数据开发人员知道具体哪一笔金额,该怎么办,比如下表,我要求统计的时候每个user_id消费的总金额不能有误,但是又不能让开发人员知道具体每一笔金额
txn_id | amount | user_id | occur_time | comment |
---|---|---|---|---|
1 | 224.00 | 2 | 2025-01-04 13:04 | |
2 | 198.00 | 1 | 2025-01-04 14:13 | |
3 | 32.00 | 1 | 2025-01-04 14:24 | |
4 | 666.00 | 3 | 2025-01-05 10:35 |
那么我们把每个user_id消费的总金额算出来,再通过随机分布来把数据打散,user_id是1的总金额没有变化,不会影响到统计数据。但是缺点是,单笔的真实性丢失了,如果我想用max或者min这种聚合就没法获取真实数据
txn_id | amount | user_id | occur_time | comment |
---|---|---|---|---|
1 | 224.00 | 2 | 2025-01-04 13:04 | |
2 | 132.45 | 1 | 2025-01-04 14:13 | |
3 | 166.55 | 1 | 2025-01-04 14:24 | |
4 | 666.00 | 3 | 2025-01-05 10:35 |
4.去尾取整
有些时候,我们不想让数据开发人员或者其他部门知道,某个业务的具体发生时间时,或者可以以牺牲某些属性精度为代价降低辨识度的时候,那么去尾取整就是一种方式,还是这张表
txn_id | amount | user_id | occur_time | comment |
---|---|---|---|---|
1 | 224.00 | 2 | 2025-01-04 13:04 | |
2 | 198.00 | 1 | 2025-01-04 14:13 | |
3 | 32.00 | 1 | 2025-01-04 14:24 | |
4 | 666.00 | 3 | 2025-01-05 10:35 |
业务部门不希望其他部门知道订单发生的具体时间戳,只需要看每个客户每天交易多少金额的笔数,那么我们就可以把datetime类型的时间戳属性,全都去尾变成date类型
txn_id | amount | user_id | occur_time | comment |
---|---|---|---|---|
1 | 224.00 | 2 | 2025-01-04 | |
2 | 198.00 | 1 | 2025-01-04 | |
3 | 32.00 | 1 | 2025-01-04 | |
4 | 666.00 | 3 | 2025-01-05 |
客户哪天交易了多少可以看到,但是具体时间看不到了。当然,这个也有问题,就是个体的精度丢失,在需要精准的场景下无法应对。
小结
实际上数据脱敏的方式远远不只这些手段,这些只是我实际工作中使用过并且有过具体实践案例的方法。数据该怎么脱敏,最终还是要以具体需求为基准,很多时候一张表可能要用到多种组合。生产数据无小事,我更建议的是单个场景单项处理,不要总期望一个方案解决所有需求场景。存储越来越不值钱的今天,一次不合适的脱敏带来的损失,可能远远高于多一份数据副本的存储和脱敏成本。
反过来说,数据也不是非要脱敏,如果系统对应的权限控制粒度做得足够好,自带的加密打码功能足以应对,那么完全可以把这部分工作交给系统。
评论

