Search code examples
regexspring-bootlogginglogbackslf4j

How to mask the userName and password in requestBody logs


Below is my request body xml and I am making rest call with this request. Having custom LoggingInterceptor to log the request and response. I want to mask the user and password in logs.

<login><credentials user="user" Password="pass"/></login>

     private void traceRequest(final HttpRequest request, final byte[] body) throws IOException {
        logger.trace(
            String.format(
                "REQUEST uri=%s, method=%s, requestBody=%s",
                request.getURI(),
                request.getMethod(),
                new String(body, "UTF-8")));
    }

Currently I am printing my logs like below:

LoggingRequestInterceptor - REQUEST uri=http://localhost:8080/, method=POST, requestBody=<login><credentials user="user" Password="pass"/></login>

Below is my logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">

    <property name="logFile" value="logs/employee.log" />
    <property name="logFile-WS" value="logs/employee-ws.log" />


    <appender name="employee" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${logFile}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${logFile}.%d{yyyy-MM-dd}.gz</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d [%thread] %-5level %logger{64} - %msg%n</pattern>
        </encoder>
    </appender>

    <appender name="mainAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${logFile-WS}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${logFile-WS}.%d{yyyy-MM-dd}.gz</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d [%thread] %-5level %logger{64} - %replace(%msg){'having masking logic for other property'}%n</pattern>
        </encoder>
    </appender>
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    <logger name="org.springframework.ws.client.MessageTracing" level="TRACE" additivity="false">
        <appender-ref ref="mainAppender" />
    </logger>

    <logger name="org.springframework.ws.server.MessageTracing" level="TRACE" additivity="false">
        <appender-ref ref="mainAppender" />
    </logger>

    <logger name="com.employee.LoggingRequestInterceptor" level="TRACE" additivity="false">
        <appender-ref ref="mainAppender" />
    </logger>


    <root level="${root-log-level:-INFO}">
        <appender-ref ref="stdout"/>
        <appender-ref ref="mainAppender"/>
    </root>
</configuration>

Please someone help me to solve this. Note: I am using spring boot 2 and slf4j logger


Solution

  • Referring to Mask sensitive data in logs with logback

    1. Add logback-spring.xml in your project.
    2. Customize regular expression in the <patternsProperty> value to match the content your want to mask.
    3. Add the MaskingPatternLayout class (Use the updated one, the one in the beginning is not working) from the above answer

    logback-spring.xml


    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <appender name="Console"
            class="ch.qos.logback.core.ConsoleAppender">
            <encoder
                class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
                <layout class="com.example.springboot.MaskingPatternLayout">
                    <patternsProperty>(?:user|Password)="([a-zA-Z0-9]+)"
                    </patternsProperty>
                    <pattern>%d [%thread] %-5level %logger{35} - %msg%n</pattern>
                </layout>
            </encoder>
        </appender>
    
        <!-- LOG everything at INFO level -->
        <root level="info">
            <appender-ref ref="Console" />
        </root>
    </configuration>
    

    HelloController class to test


    @RestController
    public class HelloController {
    
        private static final Logger logger = LoggerFactory.getLogger(HelloController.class);
    
        @RequestMapping("/")
        public String index() {
            logger.info("<login><credentials user=\"user\" Password=\"pass\"/></login>");
            return "Greetings from Spring Boot!";
        }
    
    }
    

    Expected output


    2020-04-13 12:38:47,511 [http-nio-8080-exec-1] INFO c.e.springboot.HelloController  - <login><credentials user="****" Password="****"/></login>
    

    Update

    1. Please check if "console" should be "stdout"
    <root level="${root-log-level:-INFO}">
        <appender-ref ref="console"/>
        <appender-ref ref="mainAppender"/>
    </root>  
    

    As no appender with name "console" is found.

    1. Suppose the logger is in LoggingRequestInterceptor, you need to add the "stdout" appender also.
    <logger name="com.employee.LoggingRequestInterceptor"
        level="TRACE" additivity="false">
        <appender-ref ref="stdout" />
        <appender-ref ref="mainAppender" />
    </logger>