1、了解数据脱敏之前,先了解开发,测试,生产环境的区别。
1.1开发环境
程序员进行代码的编写、调试和初步实现的环境。
数据特点:
- 使用模拟数据
典型工具:
- 开发工具:VS Code、IntelliJ IDEA、PyCharm 等。
- 本地服务:MySQL、PostgreSQL(单机版)、Redis、Docker(用于轻量级容器化开发)。
1.2测试环境
用于验证代码功能、性能、兼容性等质量指标的独立环境,需要尽可能模拟生产环境的配置。
数据特点:
- 使用脱敏后的真实数据。
- 数据需要定期备份,但允许在测试中被修改或删除。
典型工具:
- 测试工具:Jira(缺陷管理)、Postman(接口测试)、Selenium(自动化测试)、JMeter(性能测试)。
- 环境管理:Kubernetes(容器编排)、Jenkins(持续集成 / 部署)。
1.3生产环境
生产环境是面向用户提供正式服务的环境,是系统的真实运行环境,直接关系到业务的稳定性和用户体验。
核心特点:
-
功能定位
- 正式服务提供:运行稳定的代码版本,处理真实用户请求和业务数据(如支付、交易、数据存储)。
- 高可用性要求:需保障 7×24 小时不间断服务,避免单点故障。
-
配置要求
-
硬件配置:高性能服务器或云主机,支持集群部署、负载均衡和故障转移(如多节点分布式架构)。
-
软件环境:
- 采用稳定版本的操作系统、中间件和数据库(避免使用开发版或测试版软件)。
- 部署监控工具(如 Prometheus、Zabbix)、日志分析系统(如 ELK Stack)和安全防护措施(如 WAF、防火墙)。
-
-
数据特点
- 存储真实业务数据,数据安全性和完整性至关重要(需定期备份和容灾恢复)。
- 严格禁止直接修改生产数据,操作需通过应用层接口或审批流程执行。
-
访问权限
- 仅限运维团队和授权人员访问,且需通过多重身份验证(如 VPN + 二次认证)。
- 公网可直接访问(如 Web 服务),但需通过安全组、SSL 证书等确保通信安全。
-
典型工具
- 运维工具:Ansible(配置管理)、Kubernetes(容器编排)、Docker(容器化部署)。
- 安全工具:Nessus(漏洞扫描)、OWASP ZAP(安全测试)。
2、因为测试环境的安全性是低于生产环境的,所以我们测试的时候要保证数据的隔离防止数据的泄漏。
有以下6种常见的数据脱敏方案
2.1方案一:字符串替换
技术原理:通过正则表达式对部分字符串进行部分替换
public class StringMasker {
*// 手机号脱敏:13812345678 → 1385678*
public static String maskMobile(String mobile) {
return mobile.replaceAll("(\d{3})\d{4}(\d{4})", "$1****$2");
}
*// 身份证脱敏:110101199003077777 → 1101********7777*
public static String maskIdCard(String idCard) {
if (idCard.length() == 18) {
return idCard.replaceAll("(\d{4})\d{10}(\w{4})", "$1****$2");
}
return idCard; *// 处理15位旧身份证*
}
}
使用正则表达式将关键字替换成*
适用场景:
优缺点分析:
-
优点:实现简单、性能高(时间复杂度是O(n))
-
缺点:
-
无法恢复原始数据
-
正则表达式需要考虑多国数据格式差异(例如美国和中国的手机号的长度以及规则都不同)
-
存在模式被破解风险(当攻击者知道替换的模式,就可以进行撞库攻击结合多种社会手段从而获取完整数据,导致数据泄露)
- 动态脱敏手段:每次替换位置随机、使用不同符号进行替换。
- 不可逆脱敏:使用哈希、加密、令牌化等技术,确保脱敏后数据无法反向还原。
-
2.2方案二:加密算法
加密算法选型:
-
对称加密:
- 代表算法:AES
- 特点:加解密速度快,密钥管理复杂
- 适用场景:支付信息存储
-
非对称加密:
- 代表算法:RSA
- 特点:速度慢,安全性高
- 适用场景:密钥交换
-
国密算法:
- 代表算法:SM4
- 特点:符合国家标准
- 适用场景:政府/金融系统
public class AESEncryptor {
privatestaticfinal String ALGORITHM = "AES/GCM/NoPadding";
privatestaticfinalint TAG_LENGTH = 128; // 认证标签长度
public static String encrypt(String plaintext, SecretKey key) {
byte[] iv = newbyte[12]; // GCM推荐12字节IV
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(TAG_LENGTH, iv));
byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(iv) + ":" +
Base64.getEncoder().encodeToString(ciphertext);
}
// 解密方法类似...
}
密钥管理方案对比:
2.方案三:数据遮蔽
数据库中实现数据遮蔽:
-- 创建脱敏视图
CREATE VIEW masked_customers AS
SELECT
id,
CONCAT(SUBSTR(name,1,1), '***') AS name,
CONCAT(SUBSTR(mobile,1,3), '****',
SUBSTR(mobile,8,4)) AS mobile
FROM customers;
-- 使用列级权限控制
GRANT SELECT (id, name, mobile) ON masked_customers TO test_user;
创建数据脱敏视图,在视图中将关键字段做遮蔽。
在后面查询这些字段时就从视图中去查询。
//ShardingSphere(数据库的中间件)
rules: //规则数组
-!MASK //对数据进行掩码处理
tables: //用于定义需要进行掩码处理的表结构
user: //表明
columns: //列出表中要处理的列
phone: //列字段
maskAlgorithm:phone_mask //指定要适用的算法phone_mask
maskAlgorithms: //算法配置集合
phone_mask: //单个的自定义算法
type:MD5 //使用的算法类型是MD5
props: //附带的配置
salt:abcdefg123456 //加盐值(在进行哈希运算之前,把这个值加到原始数据中。这样做的目的是增加哈希结果出来的唯一性和安全性,防止哈希值被破解)
性能测试:
2.4方案四:数据替换
将原始数据和脱敏的数据保存到cache中,方便后面快速的做转换。
映射表设计:
// 使用Guava Cache实现LRU缓存
LoadingCache<String, String> dataMapping = CacheBuilder.newBuilder()
.maximumSize(100000)
.expireAfterAccess(30, TimeUnit.MINUTES)
.build(new CacheLoader<String, String>() {
public String load(String key) {
return UUID.randomUUID().toString().replace("-", "");
}
});
public String replaceData(String original) {
return dataMapping.get(original);
}
替换流程:
2.5方案五:动态脱敏
应用层实现(Spring AOP)
@Aspect
@Component
publicclass DataMaskAspect {
@Around("@annotation(requiresMasking)")
public Object maskData(ProceedingJoinPoint joinPoint, RequiresMasking requiresMasking) throws Throwable {
Object result = joinPoint.proceed();
return mask(result, requiresMasking.type());
}
private Object mask(Object data, MaskType type) {
if (data instanceof User) {
User user = (User) data;
switch(type) {
case MOBILE:
user.setMobile(MaskUtil.maskMobile(user.getMobile()));
break;
case ID_CARD:
user.setIdCard(MaskUtil.maskIdCard(user.getIdCard()));
break;
}
}
return data;
}
}
在需要做数据脱敏的字段上添加RequiresMasking注解,然后在Spring的AOP拦截器中通过工具类动态实现数据的脱敏。
数据库代理架构:
2.6方案六:K匿名化
原理:
假设医院发布的数据:
| 年龄 | 性别 | 疾病 |
|---|---|---|
| 25 | 男 | 感冒 |
| 25 | 男 | 发烧 |
| 25 | 男 | 骨折 |
当K=3时,攻击者无法获取到具体某个人的具体信息,因为三个人具有相同特征(25岁男性)。
实现步骤:
医疗数据泛化示例:
public class KAnonymity {
// 年龄泛化:精确值→范围
public static String generalizeAge(int age) {
int range = 10; // K=10
int lower = (age / range) * range;
int upper = lower + range - 1;
return lower + "-" + upper;
}
}
假设range是K值,等于10。
generalizeAge方法中,通过一定的算法,将年龄的准确值,泛化成一个区间范围。
输入28,返回20-29。
K值选择原则:
总结:
| 方案 | 安全性 | 性能 | 可逆性 | 适用场景 |
|---|---|---|---|---|
| 字符串替换 | ★★ | ★★★★ | 不可逆 | 日志/展示 |
| 加密算法 | ★★★★ | ★★ | 可逆 | 支付信息存储 |
| 数据遮蔽 | ★★★ | ★★★ | 部分可逆 | 数据库查询 |
| 数据替换 | ★★★★ | ★★ | 可逆 | 测试数据生成 |
| 动态脱敏 | ★★★★ | ★★★ | 动态可逆 | 生产环境查询 |
| K匿名化 | ★★★★★ | ★ | 不可逆 | 医疗/位置数据 |
下图是某电商平台各方案的使用占比:
3个核心建议:
- 数据分类分级:不同级别数据采用不同脱敏策略
- 定期审计:使用自动化工具扫描敏感数据泄露
- 最小化原则:能不收集的敏感数据坚决不收集