全栈项目数据脱敏怎么做?

访客 全栈框架 1

本文目录导读:

  1. 总体原则:分层脱敏,按需解密
  2. 表现层(前端)脱敏策略
  3. 服务层(后端)脱敏方案(核心)
  4. 数据存储层脱敏方案
  5. 不同角色的脱敏策略(权限分级)
  6. 全栈协同实战流程(以订单详情为例)
  7. 常见坑与最佳实践

构建一个全栈项目的数据脱敏方案,需要从前端展示、后端接口、数据库存储以及日志审计等多个层面进行系统性设计,核心目标是:在保证开发和测试效率的同时,确保敏感数据(如手机号、身份证号、银行卡号、密码等)在非必需场景下不可见或不可逆

以下是一个分层、可落地的全栈数据脱敏方案。


总体原则:分层脱敏,按需解密

  1. 存储层:静态脱敏或加密存储(最安全)。
  2. 服务层:接口返回前动态脱敏(最常用)。
  3. 日志层:彻底屏蔽或自动替换(常被忽略)。
  4. 前端层:仅做展示和脱敏(如手机号 138****1234),但这只是辅助,绝不可依赖前端做安全脱敏

表现层(前端)脱敏策略

原则:后端已经脱敏,前端只负责展示;或前端对后端已脱敏的数据进行二次格式化(如增加星号)。

常见做法

  • 后端返回已脱敏字符串:最简单,前端直接展示。
  • 前端自定义指令/过滤器(如 v-mask="phone"):适用于仅展示场景(如列表页),但隐患是如果黑客拿到原始 JSON 数据,前端代码无保护作用。
  • 后端返回原始数据,前端用自定义渲染:只推荐用在用户本人详情页(有权限校验),且需要配合前端水印防截屏。

服务层(后端)脱敏方案(核心)

这是最核心、最可控的环节,推荐使用 注解 + AOP / 拦截器 / 序列化器 的方式。

方案 1:注解 + 返回体序列化拦截(最推荐)

思路:在 DTO(数据传输对象) 或 VO(视图对象) 的字段上标注脱敏类型,在 JSON 序列化阶段自动替换。

Java (Spring Boot) 示例

  1. 定义注解 @Sensitive

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface Sensitive {
        SensitiveType type();  // 如 PHONE, ID_CARD, BANK_CARD
    }
    public enum SensitiveType {
        PHONE, ID_CARD, BANK_CARD, PASSWORD
    }
  2. 定义脱敏工具类

    public class DesensitizedUtil {
        public static String phone(String phone) {
            return phone.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
        }
        public static String idCard(String id) {
            return id.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1**********$2");
        }
        public static String password(String pwd) {
            return "******";
        }
    }
  3. 自定义 Jackson 序列化器

    @JacksonAnnotationsInside
    @JsonSerialize(using = SensitiveSerializer.class)
    public @interface Sensitive {
        SensitiveType type();
    }
    public class SensitiveSerializer extends JsonSerializer<String> {
        @Override
        public void serialize(String value, JsonGenerator gen, SerializerProvider provider) {
            // 获取当前字段上的注解
            // 根据注解类型调用 DesensitizedUtil
            gen.writeString(desensitizedValue);
        }
    }
  4. 在 VO 中使用

    public class UserVO {
        private Long id;
        private String name;
        @Sensitive(type = SensitiveType.PHONE)
        private String phone;
        @Sensitive(type = SensitiveType.PASSWORD)
        private String password;
    }

优势:无侵入、统一管理、性能高、切换方便。

方案 2:MyBatis / ORM 层脱敏(不推荐用于展示)

在从数据库读取后、返回前脱敏,优点是可控制粒度到 SQL 级别,缺点是耦合太深,通常用于数据导出场景,推荐给方案 1。

方案 3:审计日志与异常日志脱敏

常见遗漏

  • log.info("用户信息: {}", user) → 可能直接打印了身份证号。
  • Elasticsearch 收集的日志。
  • 全局异常拦截器返回的堆栈信息。

解决方案

// 方式一:在日志框架配置中,使用 MaskingLayout(如 Logback)
// 或使用 Aspect 切面拦截所有 log 方法,对敏感参数进行替换
@Aspect
@Component
public class LogDesensitizationAspect {
    @Around("execution(* *.log(..)) && args(logger,..)")
    public Object protectSensitiveInLog(ProceedingJoinPoint pjp) {
        Object[] args = pjp.getArgs();
        // 遍历参数,替换敏感字符串模式(如 3-4-4 电话模式)
        return pjp.proceed(protectedArgs);
    }
}

数据存储层脱敏方案

静态脱敏(用于开发/测试环境)

从生产库导出数据到测试库时,自动替换所有敏感字段为假数据(如所有手机号变为 13800000001),保证开发测试可用而数据不可溯源。

动态脱敏(生产中常用)

加密存储 + 按需解密

  • 存储:在 DAO 层插入前加密(AES / 国密 SM4)。
  • 查询:只有特定接口(如用户详情、金融交易)才调用解密方法;普通列表查询直接返回密文或脱敏字符串。

Java 示例(使用 MyBatis TypeHandler):

@MappedTypes(String.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class EncryptTypeHandler extends BaseTypeHandler<String> {
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, String parameter) {
        ps.setString(i, AES.encrypt(parameter));  // 加密存入数据库
    }
    @Override
    public String getNullableResult(ResultSet rs, String columnName) {
        String raw = rs.getString(columnName);
        return raw == null ? null : AES.decrypt(raw); // 自动解密
    }
}

注意:该方案对查询性能有影响(如无法用 LIKE 查询脱敏字段),需配合索引分词等值查询


不同角色的脱敏策略(权限分级)

同一个数据,不同角色看到的内容不同:

用户角色 手机号 身份证号
普通用户(本人) 完整 隐藏前6位
客服 完整前后四位 隐藏中间8位
管理员 完整 完整
其他用户 隐藏中间四位 全部隐藏

实现方式:在后端根据 SecurityContext 中的角色信息,使用策略工厂动态决定脱敏规则。


全栈协同实战流程(以订单详情为例)

  1. 前端:用户点击“查看完整手机号”。
  2. 后端:检查权限(用户本人且已通过二次验证),调用加密服务解密数据库中的 phone 字段。
  3. 服务端:记录该操作日志(已脱敏),并将解密后的完整数据返回给前端。
  4. 前端:展示完整手机号,同时添加数字水印。
  5. 数据库phone 字段始终存储加密密文,普通查询只返回脱敏后的 。

常见坑与最佳实践

  • 不要在前端做真正脱敏:前端代码是公开的,任何前端脱敏都可被绕过(查看网络请求即可看到原始数据)。
  • 统一脱敏库:所有脱敏逻辑统一到后端的一个模块,便于审计和修改。
  • 日志是最大的泄露点:务必配置日志脱敏过滤器,禁止打印敏感字段。
  • 图片/文件:身份证照片、银行卡照片等文件也需脱敏水印处理。
  • API 文档:避免在 Swagger / OpenAPI 文档中暴露敏感字段示例值。

全栈数据脱敏的最佳实践是:

数据存储加密 + 日志脱敏 + 后端通过注解/序列化器动态返回部分脱敏数据 + 前端只做展示格式美化

具体选择哪种方案,取决于你的合规需求(如等保三级、GDPR、PCI-DSS)和对性能的要求。

如果需要针对特定编程语言(如 Node.js / Python / Go)或特定框架的代码实现,可以进一步说明。

标签: 数据脱敏 全栈项目

抱歉,评论功能暂时关闭!