我们的Web应用程序需要符合PCI,即它不能存储任何信用卡号码。这个应用程序是主机系统的前端,主机系统内部处理CC号码,正如我们刚刚发现的那样,偶尔还会在其中一个响应屏幕上吐出完整的CC号码。默认情况下,这些响应的全部内容都是在调试级别记录的,并且从这些响应解析的内容也可以记录在许多不同的地方。所以我找不到这些数据泄露的源头。我必须确保在我们的日志文件中隐藏CC编号。
regex部分不是问题,我将重用我们已经在其他几个地方使用的regex。但是,对于如何使用log4j修改日志消息的一部分,我找不到任何好的来源。过滤器似乎更为有限,只能决定是否记录特定事件,但不能更改消息的内容。我也发现了
ESAPI security wrapper API
对于log4j,它一眼就能保证做我想做的事。但是,显然我需要用esapi logger类替换代码中的所有记录器——这是一个麻烦。我更喜欢更透明的解决方案。
知道如何从log4j输出中屏蔽信用卡号码吗?
更新:
基于@pgras的原始想法,这里有一个可行的解决方案:
public class CardNumberFilteringLayout extends PatternLayout {
private static final String MASK = "$1++++++++++++";
private static final Pattern PATTERN = Pattern.compile("([0-9]{4})([0-9]{9,15})");
@Override
public String format(LoggingEvent event) {
if (event.getMessage() instanceof String) {
String message = event.getRenderedMessage();
Matcher matcher = PATTERN.matcher(message);
if (matcher.find()) {
String maskedMessage = matcher.replaceAll(MASK);
@SuppressWarnings({ "ThrowableResultOfMethodCallIgnored" })
Throwable throwable = event.getThrowableInformation() != null ?
event.getThrowableInformation().getThrowable() : null;
LoggingEvent maskedEvent = new LoggingEvent(event.fqnOfCategoryClass,
Logger.getLogger(event.getLoggerName()), event.timeStamp,
event.getLevel(), maskedMessage, throwable);
return super.format(maskedEvent);
}
}
return super.format(event);
}
}
笔记:
-
我戴面具
+
而不是
*
,因为我想区分CID被此记录器屏蔽的时间、后端服务器屏蔽的时间或其他任何情况。
-
我使用简单的正则表达式,因为我不担心误报
代码经过了单元测试,所以我相当确信它可以正常工作。当然,如果你发现有改进的可能,请告诉我:—)