什么是数据脱敏?
数据脱敏是一种保护数据安全的技术,指对某些敏感信息通过脱敏规则进行数据转换,目的是使数据不可为第三方使用,实现敏感隐私数据的可靠保护。
为什么需要数据脱敏?
随着社会的发展,特别是快递和互联网的普及,人们在互联网上变成了一个个透明的个体,没有隐私可言。你的姓名、家庭住址、手机号、身份证号、银行卡号、甚至是银行卡密码都不再是你一个人秘密!各种层出不穷的数据泄露滋生了许多潜在的犯罪行为,为此国家也出台了相关的政策法规用以保护人们的隐私。
保护数据安全的的常见方式主要包括数据加密和数据脱敏,对用户敏感信息进行数据加密,即使出现数据泄露,犯罪嫌疑人拿到的也是不可识别的加密数据,可以有效的阻止进一步的犯罪活动。
数据脱敏,程序开发中再程序执行的一些关键步骤往往需要打印一些关键信息以便观察程序运行是否正常,同时在程序出现异常的情况也可以根据日志信息去追踪、排查出现异常的原因,以便及时修正程序。
说道这里,之前在一些代码里经常看到类似下面的日志:
log.info("查询统计数据失败");
log.error("用户创建订单异常");
咋一看貌似没啥问题,但是仔细一想,日志是用来记录程序的运行轨迹同时方便在程序出现异常的时候排查问题的,上面的日志其实属于无效日志,我们只知道失败了,但是不知道是谁失败了,失败的原因是什么!这时就需要我们打印日志的时候不但需要打印出当时的现象,还需要打印出相关的关键信息,比如是哪个用户创建订单异常了,异常的原因是库存不足还是网络不好等等原因。有了这些信息我们才可以在排查问题的时候快速定位问题并进行修复。
到这里就有一个问题了,敏感数据在数据库通常是加密处理的,但是在程序运行的时候加密数据需要被解密,同时我们需要在程序运行的一些关键点打印信息,如果是用户的敏感数据直接被输出到日志,如果日志文件泄露,也会出现相关的安全问题,这里就需要使用日志脱敏,脱敏以后我们打印出来的日志就是这样的了:
log.error("用户 {} 创建订单异常,原因是 {}", user.getUserName() ,e.getMessage());
// 打印出来的数据大概就是这个样子
用户 张** 创建订单异常,原因是 用户收货地址不存在
今天这里讲到的数据安全保护主要是通过对日志敏感数据进行掩码处理,下面我们一起来探究具体怎么实现。
怎么实现数据脱敏?
现有如下需求:
要求所有程序的日志信息必须脱敏处理,规则如下:
姓名 张三丰 ---> 张**
手机号 13456789900 ---> 134****9900
身份证号 32489919990909432X ---> 3248**********432X
电子邮箱 10000@qq.com ---> 100***@qq.com
家庭住址
银行卡号
......
需求看起来很简单,只要学过编程的人都能实现,直接写一个掩码工具处理类,数据日志的时候掩码处理一下就 ok (这里以 java 做演示),
上代码
/**
* 敏感信息掩码处理工具类
*/
@Slf4j
public class MaskUtils {
/**
* 手机号掩码处理 15312345567 --> 153****5567
*
* @param mobile 手机号
* @return 处理后的手机号
*/
public static String maskMobile(String mobile) {
if (!StringUtils.hasText(mobile)) {
return "";
}
int length = mobile.length();
if (length != 11) {
log.error("脱敏处理失败,{} 不是手机号,请确认!", mobile);
return mobile;
}
return mobile.substring(0, 3) + "****" + mobile.substring(7);
}
/**
* 姓名掩码处理 王语嫣 --> 王**
*
* @param name 姓名
* @return 处理后的姓名
*/
public static String maskName(String name) {
if (!StringUtils.hasText(name)) {
return "";
}
return name.charAt(0) + "**";
}
/**
* 身份证号掩码处理 31033219990909432X --> 3103**********432X
*
* @param idCardNo 身份证号码
* @return 处理后的身份证号码
*/
public static String maskIdCardNo(String idCardNo) {
if (!StringUtils.hasText(idCardNo)) {
return "";
}
int length = idCardNo.length();
if (length != 15 && length != 18) {
log.error("脱敏处理失败,{} 不是身份证,请确认!", idCardNo);
return idCardNo;
}
if (length == 15) {
return idCardNo.substring(0, 4) + "**********" + idCardNo.substring(11);
}
return idCardNo.substring(0, 4) + "**********" + idCardNo.substring(14);
}
}
测试一下:
public static void main(String[] args) {
String phone = "15312345567";
String maskMobile = maskMobile(phone);
log.info("maskMobile = {}", maskMobile);
String name = "王语嫣";
String maskName = maskName(name);
log.info("maskName = {}", maskName);
String idCard = "31033219990909432X";
String maskIdCardNo = maskIdCardNo(idCard);
log.info("maskName = {}", maskIdCardNo);
}
// [com.info.examples.log.MaskUtils:67] maskMobile = 153****5567
// [com.info.examples.log.MaskUtils:71] maskName = 王**
// [com.info.examples.log.MaskUtils:75] maskName = 3103**********432X
一切都朝着我们预计的方向发展,生活是如此美好!有了这个工具类,只需要在打印日志之前调用下对应的方法,问题就完美解决了。
我们工作中日志除了上面那种简单的,还有这样的:
{"email":"10000@qq.com","idNo":"31033219990909432X","mobile":"15312345567","name":"王语嫣"}
甚至还有这样的:
"{\"email\":\"10000@qq.com\",\"idNo\":\"31033219990909432X\",\"mobile\":\"15312345567\",\"name\":\"王语嫣\"}"
如果遇到这种日志,上面的方法好像就不好处理了呢?
今天的内容到这里暂告一段落,谢谢各位阅读,如有不妥之处还请指正,感激不尽。
欲知后事如何,且听下回分解。