我在我的 Spring Boot 项目的 logback 配置中使用下面的 Logstash 编码器。
<encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<pattern>
<pattern>
{
"creation_timestamp": "%d{yyyy-MM-dd'T'HH:mm:ss, UTC}",
"msg": "%msg",
"log_type": "%level",
}
</pattern>
<omitEmptyFields>true</omitEmptyFields>
</pattern>
</providers>
</encoder>
我想屏蔽 json 日志消息中的敏感数据。我尝试了以下方法来掩盖键“Code”的值。但这不起作用。
"msg": "%replace(%msg){'\"Code\":'.*'', '\"Code\":'xxx''}",
如何在 Logstash 附加程序中屏蔽 json 值?
我能够通过编写 ValueMasker 的自定义实现来屏蔽敏感数据
需要两个组件:
ValueMasker
jsonGeneratorDecorator
中声明
logback.xml
package com.mask;
import com.fasterxml.jackson.core.JsonStreamContext;
import net.logstash.logback.mask.ValueMasker;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.IntStream;
public class SensitiveMaskingPatternLayout implements ValueMasker {
private Pattern multilinePattern = Pattern.compile("\\\"msg\\\"\\s*:\\s*\\\"(.*?)\\\"", Pattern.MULTILINE);;
private List<String> maskPatterns = new ArrayList<>();
private String maskMessage(String message) {
StringBuilder sb = new StringBuilder(message);
Matcher matcher = multilinePattern.matcher(sb);
while (matcher.find()) {
IntStream.rangeClosed(1, matcher.groupCount()).forEach(group -> {
if (matcher.group(group) != null) {
IntStream.range(matcher.start(group), matcher.end(group)).forEach(i -> sb.setCharAt(i, 'x'));
}
});
}
return sb.toString();
}
@Override
public Object mask(JsonStreamContext context, Object value) {
if (value instanceof CharSequence) {
return maskMessage((String) value);
}
return value;
}
}
<configuration>
<appender name="mask" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<pattern>
<pattern>
{
"msg": "%msg",
"log_type": "%level"
}
</pattern>
<omitEmptyFields>true</omitEmptyFields>
</pattern>
</providers>
<logLevel>
INFO
</logLevel>
<jsonGeneratorDecorator class="net.logstash.logback.mask.MaskingJsonGeneratorDecorator">
<valueMasker class="com.mask.SensitiveMaskingPatternLayout"/>
</jsonGeneratorDecorator>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="mask" />
</root>
</configuration>
示例:
package com.example;
import java.util.HashMap;
import java.util.Map;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class App {
private static final Logger logger = LoggerFactory.getLogger(App.class);
public static void main(String[] args) {
Map<String, String> user = new HashMap<>();
user.put("user_id", "97588");
user.put("email_id", "[email protected]");
user.put("msg", "hello world");
JSONObject userDetails = new JSONObject(user);
logger.info("MaskingPatternExample log from {}" + userDetails);
}
}
{"msg":"MaskingPatternExample log from {}{\"email_id\":\"[email protected]\",\"msg\":\"xxxxxxxxxxx\",\"user_id\":\"97588\"}","log_type":"INFO"}
更多文档。
ValueMasker
方法对我不起作用。如果您遇到同样的问题,这就是有效的方法:
如果您注意到
LoggingEventCompositeJsonEncoder
中的 logback.xml
,它有这些名为 <providers>
的字段。
进一步检查,你会发现这些
LoggingEventJsonProviders
基本上设置了我们编码器中的所有json字段。
因此,如果你有一个名为
<message>
的字段,它是一个提供者,你可以通过扩展 AbstractFieldJsonProvider
类来修改该字段的内容,如下所示:
public class ModifyingProvider extends AbstractFieldJsonProvider < ILoggingEvent > {
private final Pattern[] maskPatterns;
public ModifyingProvider() {
maskPatterns = new Pattern[] {
Pattern.compile("\\b[0-9]{2}-[0-9]{2}-[0-9]{4}\\b"), // DOB pattern (DD-MM-YYYY)
// Add more patterns as needed
};
}
private String maskData(String message) {
StringBuilder maskedMessage = new StringBuilder(message);
for (Pattern pattern: maskPatterns) {
Matcher matcher = pattern.matcher(maskedMessage);
while (matcher.find()) {
String match = matcher.group();
String maskedValue = mask(match);
maskedMessage.replace(matcher.start(), matcher.end(), maskedValue);
}
}
return maskedMessage.toString();
}
private String mask(String originalValue) {
// Masking Logic
}
@Override
public void writeTo(JsonGenerator generator, ILoggingEvent event) throws IOException {
// Modify the log message or provide an alternative message here
String modifiedMessage = modifyMessage(originalMessage);
// Write the modified message to the JSON output
generator.writeStringField("message", modifiedMessage);
}
private String modifyMessage(String originalMessage) {
return maskData(originalMessage);
}
然后在您的
logback.xml
中,只需替换所需的 <provider>
标签,或者在本例中将 <message>
标签替换为 <provider class="path.to.your.class.ModifyingProvider"/>
。