Маскировать конфиденциальные данные в журналах с logback
мне нужно иметь возможность искать событие для любого из нескольких шаблонов и заменять текст в шаблоне скрытым значением. Это функция в нашем приложении, предназначенная для предотвращения попадания конфиденциальной информации в журналы. Поскольку информация может поступать из самых разных источников, применять фильтры на всех входах нецелесообразно. Кроме того, есть использование toString () за пределами ведения журнала, и я не хочу, чтобы toString() равномерно маскировался для всех вызовов (только лесозаготовительный.)
Я попытался использовать метод %replace в logback.XML-код:
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %replace(%msg){'f k="pin">(.*?)</f','f k="pin">**********</f'}%n</pattern>
Это было успешно (после замены угловых скобок символами), но он может заменить только один шаблон. Я также хотел бы выполнить эквивалент
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %replace(%msg){'pin=(.*?),','pin=**********,'}%n</pattern>
в то же время, но не можем. Невозможно замаскировать два шаблона в one %replace.
другой способ, который был свободно обсужден на interblags, расширяет что-то в иерархии appender/encoder/layout, но каждая попытка перехватить ILoggingEvent привела к коллапсу всей системы, обычно через ошибки создания экземпляра или UnsupportedOperationException.
например, я попытался расширить PatternLayout:
@Component("maskingPatternLayout")
public class MaskingPatternLayout extends PatternLayout {
@Autowired
private Environment env;
@Override
public String doLayout(ILoggingEvent event) {
String message=super.doLayout(event);
String patternsProperty = env.getProperty("bowdleriser.patterns");
if( patternsProperty != null ) {
String[] patterns = patternsProperty.split("|");
for (int i = 0; i < patterns.length; i++ ) {
Pattern pattern = Pattern.compile(patterns[i]);
Matcher matcher = pattern.matcher(event.getMessage());
matcher.replaceAll("*");
}
} else {
System.out.println("Bowdleriser not cleaning! Naughty strings are getting through!");
}
return message;
}
}
и затем настройка logback.в XML
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<layout class="com.touchcorp.touchpoint.utils.MaskingPatternLayout">
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</layout>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/touchpoint.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>logs/touchpoint.%i.log.zip</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>3</maxIndex>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>10MB</maxFileSize>
</triggeringPolicy>
<encoder>
<layout class="com.touchcorp.touchpoint.utils.MaskingPatternLayout">
<pattern>%date{YYYY-MM-dd HH:mm:ss} %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
</layout>
</encoder>
</appender>
<logger name="com.touchcorp.touchpoint" level="DEBUG" />
<logger name="org.springframework.web.servlet.mvc" level="TRACE" />
<root level="INFO">
<appender-ref ref="FILE" />
<appender-ref ref="STDOUT" />
</root>
</configuration>
Я пробовал много других вставок, поэтому мне было интересно, действительно ли кто-то достиг того, что я пытаюсь, и могут ли они предоставить любые подсказки или решение.
2 ответов
вам нужно обернуть макет с помощью LayoutWrappingEncoder
. А также я считаю, что вы не можете использовать spring здесь, поскольку logback не управляется spring.
вот обновленный класс.
public class MaskingPatternLayout extends PatternLayout {
private String patternsProperty;
public String getPatternsProperty() {
return patternsProperty;
}
public void setPatternsProperty(String patternsProperty) {
this.patternsProperty = patternsProperty;
}
@Override
public String doLayout(ILoggingEvent event) {
String message = super.doLayout(event);
if (patternsProperty != null) {
String[] patterns = patternsProperty.split("\|");
for (int i = 0; i < patterns.length; i++) {
Pattern pattern = Pattern.compile(patterns[i]);
Matcher matcher = pattern.matcher(event.getMessage());
if (matcher.find()) {
message = matcher.replaceAll("*");
}
}
} else {
}
return message;
}
}
и образец logback.в XML
<appender name="fileAppender1" class="ch.qos.logback.core.FileAppender">
<file>c:/logs/kp-ws.log</file>
<append>true</append>
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="com.kp.MaskingPatternLayout">
<patternsProperty>.*password.*|.*karthik.*</patternsProperty>
<pattern>%d [%thread] %-5level %logger{35} - %msg%n</pattern>
</layout>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="fileAppender1" />
</root>
обновление
здесь его лучший подход, установить шаблон во время init себя. таким образом, мы можем избежать воссоздания шаблона снова и снова, и эта реализация близка к реалистичной usecase.
public class MaskingPatternLayout расширяет 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) {
for (int i = matcher.start(group); i < matcher.end(group); i++) {
message.setCharAt(i, '*');
}
}
group++;
}
}
}
return message.toString();
}
}
и обновленный файл конфигурации.
<appender name="fileAppender1" class="ch.qos.logback.core.FileAppender">
<file>c:/logs/kp-ws.log</file>
<append>true</append>
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="com.kp.MaskingPatternLayout">
<patternsProperty>(password)|(karthik)</patternsProperty>
<pattern>%d [%thread] %-5level %logger{35} - %msg%n</pattern>
</layout>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="fileAppender1" />
</root>
выход
My username=test and password=*******
из документации:
replace(p){r, t}
шаблон p
может быть сколь угодно сложным и, в частности, может содержать несколько ключевых слов преобразования.
столкнувшись с той же проблемой, что и замена 2 шаблонов в сообщении, я просто попытался chain
так p
это просто вызов replace, в моем случае:
%replace( %replace(%msg){'regex1', 'replacement1'} ){'regex2', 'replacement2'}
работала отлично, хотя мне интересно, если я толкаю его немного и p
может быть действительно что угодно сложной.