数据脱敏是对敏感数据进行变形处理,在保留数据特征的同时保护隐私信息。本文详细介绍 IMS 系统中的数据脱敏策略与实现方案,满足等保和合规要求。
脱敏字段分类
识别并分类需要脱敏的敏感字段:
/* 敏感字段配置 */
const SENSITIVE_FIELDS = {
/* 个人信息 */
'name': { type: 'name', level: 'medium' },
'phone': { type: 'phone', level: 'high' },
'id_card': { type: 'id_card', level: 'high' },
'email': { type: 'email', level: 'medium' },
'address': { type: 'address', level: 'medium' },
'birthday': { type: 'date', level: 'low' },
/* 金融信息 */
'bank_card': { type: 'bank_card', level: 'high' },
'account': { type: 'account', level: 'high' },
'password': { type: 'password', level: 'critical' },
'pay_password': { type: 'password', level: 'critical' },
/* 企业信息 */
'company_name': { type: 'name', level: 'low' },
'legal_person': { type: 'name', level: 'medium' },
'credit_code': { type: 'code', level: 'high' },
};
/* 敏感级别 */
const SENSITIVE_LEVELS = {
LOW: 1, // 低敏感性,可显示部分
MEDIUM: 2, // 中敏感性,需要部分掩码
HIGH: 3, // 高敏感性,需要大部分掩码
CRITICAL: 4, // 极高敏感性,完全隐藏
};
脱敏算法实现
针对不同类型数据的脱敏策略:
/* 数据脱敏服务 */
class DataMaskingService {
/* 手机号脱敏:138****5678 */
maskPhone(phone) {
if (!phone) return '';
return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2');
}
/* 身份证脱敏:320*******1234567 */
maskIdCard(idCard) {
if (!idCard) return '';
return idCard.replace(/(\d{3})\d{10}(\d{4})/, '$1*******$2');
}
/* 银行卡脱敏:6222 **** **** 5678 */
maskBankCard(card) {
if (!card) return '';
return card.replace(/(\d{4})\d{8}(\d{4})/, '$1 **** **** $2');
}
/* 姓名脱敏:张*三 */
maskName(name) {
if (!name) return '';
const len = name.length;
if (len === 1) return name;
if (len === 2) return name[0] + '*';
return name[0] + '*'.repeat(len - 2) + name[len - 1];
}
/* 邮箱脱敏:t***@example.com */
maskEmail(email) {
if (!email) return '';
const [local, domain] = email.split('@');
if (local.length <= 2) {
return local[0] + '***@' + domain;
}
return local[0] + '***' + local[local.length - 1] + '@' + domain;
}
/* 密码完全隐藏 */
maskPassword(password) {
return '******';
}
/* 地址脱敏:保留省市 */
maskAddress(address) {
if (!address) return '';
/* 只保留前 N 个字符或省市信息 */
const parts = address.split(' ');
if (parts.length >= 2) {
return parts[0] + ' ' + parts[1] + '****';
}
return address.substring(0, 6) + '****';
}
}
自动脱敏中间件
在 API 响应层面自动应用脱敏:
/* 响应脱敏中间件 */
class MaskingMiddleware {
constructor(maskingService) {
this.maskingService = maskingService;
}
process(data, fields, context) {
if (!data || !fields) return data;
/* 检查用户权限 */
const userLevel = getUserSensitivityLevel(context.user);
const result = {};
for (const [key, value] of Object.entries(data)) {
const config = SENSITIVE_FIELDS[key];
if (!config) {
result[key] = value;
continue;
}
/* 检查是否需要脱敏 */
if (config.level > userLevel) {
result[key] = this.maskingService.mask(value, config.type);
} else {
result[key] = value;
}
}
return result;
}
mask(value, type) {
const method = 'mask' + type[0].toUpperCase() + type.slice(1);
return this.maskingService[method]
? this.maskingService[method](value)
: '***';
}
}
脱敏策略原则
- 一致性:同一字段在所有场景使用相同脱敏规则
- 可逆性:必要时可还原(如管理员权限)
- 可读性:保留足够信息便于识别
- 性能:脱敏操作不应影响系统响应
字段级别脱敏配置
支持按业务模块配置脱敏策略:
/* 模块脱敏配置 */
const MODULE_MASKING_CONFIG = {
'customer': {
'name': { enabled: true, type: 'name' },
'phone': { enabled: true, type: 'phone', roles: ['admin', 'sales'] },
'id_card': { enabled: true, type: 'id_card', roles: ['admin'] },
},
'order': {
'buyer_name': { enabled: true, type: 'name' },
'buyer_phone': { enabled: true, type: 'phone' },
},
'finance': {
'account': { enabled: true, type: 'account', roles: ['admin', 'finance'] },
'bank_card': { enabled: true, type: 'bank_card', roles: ['admin', 'finance'] },
}
};
/* 使用配置脱敏 */
function maskByModule(data, module, userRole) {
const config = MODULE_MASKING_CONFIG[module];
if (!config) return data;
const result = { ...data };
for (const [field, fieldConfig] of Object.entries(config)) {
if (!fieldConfig.enabled) continue;
/* 检查角色权限 */
if (fieldConfig.roles && !fieldConfig.roles.includes(userRole)) {
result[field] = maskValue(result[field], fieldConfig.type);
}
}
return result;
}
日志脱敏
防止敏感信息写入日志:
/* 日志脱敏拦截器 */
class LogMaskingInterceptor {
constructor() {
this.fieldPatterns = [
'password', 'passwd', 'pwd',
'token', 'access_token',
'phone', 'id_card',
'bank_card', 'cvv'
];
}
mask(obj) {
if (!isObject(obj)) return obj;
const result = {};
for (const [key, value] of Object.entries(obj)) {
if (this.shouldMask(key)) {
result[key] = '***MASKED***';
} else if (isObject(value)) {
result[key] = this.mask(value);
} else {
result[key] = value;
}
}
return result;
}
shouldMask(key) {
const lowerKey = key.toLowerCase();
return this.fieldPatterns.some(p => lowerKey.includes(p));
}
}
审计与合规
脱敏操作的完整审计追踪:
/* 脱敏审计日志 */
const MASKING_AUDIT_LOG = {
table: 'audit_masking',
fields: ['id', 'operator_id', 'operation',
'module', 'field', 'action',
'timestamp', 'ip']
};
/* 记录脱敏操作 */
async logMaskingOperation(operator, module, field, action) {
await db.insert(MASKING_AUDIT_LOG.table, {
operator_id: operator.id,
operation: 'data_masking',
module,
field,
action,
timestamp: now(),
ip: operator.ip
});
}
总结
- 字段分类:按敏感级别分类管理
- 算法实现:针对不同类型定制脱敏规则
- 中间件处理:API 响应自动脱敏
- 角色权限:按角色控制脱敏程度
- 日志安全:日志中不出现敏感信息
- 审计追踪:记录所有脱敏操作