Logback configuration to mask specific log data

廉价感情. 提交于 2021-02-10 09:38:47

问题


I have a Spring Boot web app and am using logback as my logging solution. I have been looking through the documentation and cannot find an easy or 'correct' way to mask private/specific data (Personal info, credit card #s, etc.).

The closest I have been able to find is Logback filters, however the use case around those seems to be more about omitting logs that match specific criteria, I am simply looking to mask all, application wide, logs.

This seems like such a basic question and I am certain I am missing something super basic, but any shove or point in the right direction is very much appreciated.

I am also not locked into logback so if there is an easier/better way to do this using log4j2 for example I am all ears


回答1:


To mask configurable fields, you need to create MaskingPatternLayout like below,

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.spi.ILoggingEvent;

public class MaskingPatternLayout extends PatternLayout {

  private String patternsProperty;
  private Optional<Pattern> pattern;

  public String getPatternsProperty() {
    return patternsProperty;
  }

  public void setPatternsProperty(String patternsProperty) {
    this.patternsProperty = patternsProperty;
    if (this.patternsProperty != null) {
      this.pattern = Optional.of(Pattern.compile(patternsProperty, Pattern.MULTILINE));
    } else {
      this.pattern = Optional.empty();
    }
  }

  @Override
  public String doLayout(ILoggingEvent event) {
    final StringBuilder message = new StringBuilder(super.doLayout(event));

    if (pattern.isPresent()) {
      Matcher matcher = pattern.get().matcher(message);
      while (matcher.find()) {

        int group = 1;
        while (group <= matcher.groupCount()) {
          if (matcher.group(group) != null) {
            final int startGrpIndex = matcher.start(group);
            final int endGrpIndex = matcher.end(group);
            final int diff = endGrpIndex - startGrpIndex + 1;
            int startIndex = startGrpIndex + diff;
            final int endIndex1 = message.indexOf(",", startIndex);
            final int endIndex2 = message.indexOf(" ", startIndex);
            final int endIndex3 = message.indexOf(")", startIndex);
            final int endIndex4 = message.indexOf("\n", startIndex);

            final Integer endIndex = getSmallestInt(
              Arrays.asList(Integer.valueOf(endIndex1), Integer.valueOf(endIndex2), Integer.valueOf(endIndex3), Integer.valueOf(endIndex4)));
            if (endIndex == null || endIndex <= 0) {
              continue;
            }

            for (int i = startIndex; i < endIndex; i++) {
              message.setCharAt(i, '*');
            }
          }
          group++;
        }
      }
    }
    return message.toString();
  }

  private Integer getSmallestInt(List<Integer> integerList) {

    return integerList.stream().filter(integer -> integer > 0).reduce((x, y) -> x < y ? x : y).get();
  }

}

Need to add an encoder in logback.xml appenders -

<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
      <layout class="com.adgiants.config.MaskingPatternLayout">
        <patternsProperty>(password)|(email)</patternsProperty>
        <pattern>%d [%thread] %-5level %logger{35} - %msg%n</pattern>
      </layout>
</encoder>

This configuration will scan all your log statements and match for words like "password" or "email"(whichever you have configured in the logback.xml encoder), its values will be replaced with ****

E.g

log.info("Received sign-up request, password=DummyPassword@123");

In logs above statement will be shown as,

Received sign-up request, password=*****************


来源:https://stackoverflow.com/questions/50575094/logback-configuration-to-mask-specific-log-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!