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

如何在Spring Boot应用中对RestTemplate日志中的用户名、密码信息脱敏

Spring Boot中RestTemplate日志敏感信息脱敏方案

下面是几种实用的方法,用来给RestTemplate日志里的用户名、密码、client_secret这类敏感字段脱敏:

方法一:自定义请求拦截器,在请求链路中脱敏

通过实现ClientHttpRequestInterceptor,在请求发送前替换请求体里的敏感参数,这样日志输出的就是脱敏后的内容。

实现脱敏拦截器

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SensitiveDataInterceptor implements ClientHttpRequestInterceptor {

    // 匹配表单格式的敏感参数
    private static final Pattern SENSITIVE_PARAMS_PATTERN = Pattern.compile(
            "(password|client_secret|username)=([^&]+)", Pattern.CASE_INSENSITIVE);

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        // 只处理表单类型的请求
        if (body.length > 0 && request.getHeaders().getContentType() != null &&
                request.getHeaders().getContentType().toString().contains("application/x-www-form-urlencoded")) {
            String bodyStr = new String(body, StandardCharsets.UTF_8);
            Matcher matcher = SENSITIVE_PARAMS_PATTERN.matcher(bodyStr);
            // 替换敏感参数值为***
            String maskedBody = matcher.replaceAll(matchResult -> matchResult.group(1) + "=***");
            body = maskedBody.getBytes(StandardCharsets.UTF_8);
        }
        return execution.execute(request, body);
    }
}

注册拦截器到RestTemplate

@Bean
public RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();
    restTemplate.getInterceptors().add(new SensitiveDataInterceptor());
    return restTemplate;
}

如果是JSON格式的请求,需要把正则替换成JSON字段匹配逻辑,比如用Jackson解析后替换敏感字段再序列化。

方法二:Logback自定义转换器,日志层面脱敏

直接在日志输出环节修改消息内容,不影响实际请求,适合只需要日志脱敏的场景。

实现日志脱敏转换器

import ch.qos.logback.classic.pattern.ClassicConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RestTemplateSensitiveDataConverter extends ClassicConverter {

    // 匹配RestTemplate日志里的敏感字段格式,比如password=[FooBar..]
    private static final Pattern SENSITIVE_DATA_PATTERN = Pattern.compile(
            "(password|client_secret|username)=\\[([^\\]]+)\\]", Pattern.CASE_INSENSITIVE);

    @Override
    public String convert(ILoggingEvent event) {
        String message = event.getMessage();
        Matcher matcher = SENSITIVE_DATA_PATTERN.matcher(message);
        // 替换为***
        return matcher.replaceAll(matchResult -> matchResult.group(1) + "=[***]");
    }
}

配置Logback使用转换器

在logback-spring.xml里添加以下配置:

<configuration>
    <!-- 注册自定义转换器 -->
    <conversionRule conversionWord="maskedMessage" converterClass="com.yourpackage.RestTemplateSensitiveDataConverter"/>

    <!-- 控制台输出用脱敏后的消息 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %maskedMessage%n</pattern>
        </encoder>
    </appender>

    <!-- 给RestTemplate的日志单独配置 -->
    <logger name="org.springframework.web.client.RestTemplate" level="DEBUG" additivity="false">
        <appender-ref ref="CONSOLE"/>
    </logger>

    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
    </root>
</configuration>

方法三:替换默认日志拦截器,定制日志输出

RestTemplate默认用LoggingRequestInterceptor记录请求日志,我们可以自定义这个拦截器,在日志输出前脱敏。

实现脱敏日志拦截器

import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.client.LoggingRequestInterceptor;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MaskedLoggingRequestInterceptor extends LoggingRequestInterceptor {

    private static final Pattern SENSITIVE_PARAMS_PATTERN = Pattern.compile(
            "(password|client_secret|username)=([^&]+)", Pattern.CASE_INSENSITIVE);

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        if (body.length > 0 && logger.isDebugEnabled()) {
            String bodyStr = new String(body, StandardCharsets.UTF_8);
            Matcher matcher = SENSITIVE_PARAMS_PATTERN.matcher(bodyStr);
            String maskedBody = matcher.replaceAll("$1=***");
            // 输出脱敏后的日志
            logger.debug("Writing [{}] as \"{}\"", maskedBody, request.getHeaders().getContentType());
        }
        return execution.execute(request, body);
    }
}

注册自定义拦截器

@Bean
public RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();
    // 移除默认的日志拦截器
    restTemplate.getInterceptors().removeIf(interceptor -> interceptor instanceof LoggingRequestInterceptor);
    // 添加自定义脱敏日志拦截器
    restTemplate.getInterceptors().add(new MaskedLoggingRequestInterceptor());
    return restTemplate;
}

各方法优缺点对比

  • 请求拦截器:从请求源头处理,不仅日志脱敏,还能避免其他环节泄露敏感数据,但需要适配不同的请求格式(表单、JSON等)。
  • Logback转换器:只作用于日志层,不影响业务逻辑,配置简单,适合仅需日志脱敏的场景。
  • 自定义日志拦截器:贴合RestTemplate原有日志逻辑,输出格式和原日志一致,无需修改全局日志配置。

内容的提问来源于stack exchange,提问作者user352290

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 05:43:16