You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JAX-RS请求敏感字段日志脱敏方案技术问询

解决JAX-RS日志中敏感字段的混淆问题

针对你遇到的JAX-RS服务日志记录敏感数据的问题,我们可以通过自定义字段混淆逻辑+改造日志过滤器的方式来解决,核心思路是识别带@SensitiveData注解的字段,在日志输出前替换为掩码内容,同时不影响原始请求的业务处理。

步骤1:确保@SensitiveData注解可被运行时识别

如果还没定义这个注解,先创建一个运行时保留的注解类:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface SensitiveData {
}

步骤2:实现敏感字段混淆工具类

这个类负责通过反射遍历请求对象的字段,识别并混淆带注解的敏感数据,同时返回对象副本(避免修改原始请求):

import java.lang.reflect.Field;

public class SensitiveDataObfuscator {

    public static <T> T obfuscateSensitiveFields(T request) {
        if (request == null) {
            return null;
        }

        try {
            // 创建对象副本,防止修改原始请求数据
            T clonedRequest = (T) request.getClass().getDeclaredConstructor().newInstance();
            Field[] fields = request.getClass().getDeclaredFields();

            for (Field field : fields) {
                field.setAccessible(true);
                Object value = field.get(request);

                if (field.isAnnotationPresent(SensitiveData.class) && value != null) {
                    // 这里可以自定义混淆规则:比如密码用***,手机号保留前3后4位
                    field.set(clonedRequest, "***");
                } else {
                    field.set(clonedRequest, value);
                }
            }

            return clonedRequest;
        } catch (Exception e) {
            // 处理失败时fallback到原始对象(也可以根据需求抛出异常)
            return request;
        }
    }
}

步骤3:改造JAX-RS日志过滤器

修改你现有的日志过滤器,不再直接序列化原始请求,而是先用混淆工具处理后再记录:

import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.ext.Provider;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import com.fasterxml.jackson.databind.ObjectMapper;

@Provider
public class RequestLoggingFilter implements ContainerRequestFilter {

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        // 读取并重置请求体(避免后续业务无法读取)
        InputStream inputStream = requestContext.getEntityStream();
        byte[] requestBodyBytes = inputStream.readAllBytes();
        requestContext.setEntityStream(new ByteArrayInputStream(requestBodyBytes));

        // 解析请求对象(实际场景可根据请求路径/资源方法动态获取类型)
        SetImportantDataRequest originalRequest = objectMapper.readValue(requestBodyBytes, SetImportantDataRequest.class);

        // 混淆敏感字段
        SetImportantDataRequest obfuscatedRequest = SensitiveDataObfuscator.obfuscateSensitiveFields(originalRequest);

        // 记录处理后的日志
        String logContent = objectMapper.writeValueAsString(obfuscatedRequest);
        // 这里替换成你的日志框架(比如SLF4J的logger)
        System.out.println("Incoming request: " + logContent);
    }
}

额外优化建议

  • 动态识别请求类型:如果你的API有多种请求类,可以通过requestContext获取资源方法的参数类型,动态解析请求体对应的Java类,不用硬编码SetImportantDataRequest。
  • 自定义混淆策略:针对不同类型的敏感数据(手机号、身份证、密码),可以在工具类里添加不同的混淆逻辑,比如手机号处理为138****1234。
  • 响应日志处理:如果响应中也有敏感数据,同样可以用类似的方式改造ContainerResponseFilter,对响应对象做混淆处理后再记录。

内容的提问来源于stack exchange,提问作者Arsen Y.M.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:38:40