Java 如何用Log4J屏蔽日志文件中的信用卡号?

Java 如何用Log4J屏蔽日志文件中的信用卡号?,java,log4j,credit-card,mask,Java,Log4j,Credit Card,Mask,我们的web应用程序需要符合PCI标准,即它不能存储任何信用卡号。该应用程序是一个大型机系统的前端,该系统在内部处理抄送号码,正如我们刚刚发现的那样,偶尔仍会在其响应屏幕上显示完整的抄送号码。默认情况下,这些响应的全部内容都记录在调试级别,从中解析的内容也可以记录在许多不同的地方。所以我无法找到这些数据泄露的来源。我必须确保抄送号码在我们的日志文件中被屏蔽 regex部分不是问题,我将重用我们在其他几个地方已经使用的regex。然而,关于如何使用Log4J修改日志消息的一部分,我找不到任何好的来

我们的web应用程序需要符合PCI标准,即它不能存储任何信用卡号。该应用程序是一个大型机系统的前端,该系统在内部处理抄送号码,正如我们刚刚发现的那样,偶尔仍会在其响应屏幕上显示完整的抄送号码。默认情况下,这些响应的全部内容都记录在调试级别,从中解析的内容也可以记录在许多不同的地方。所以我无法找到这些数据泄露的来源。我必须确保抄送号码在我们的日志文件中被屏蔽

regex部分不是问题,我将重用我们在其他几个地方已经使用的regex。然而,关于如何使用Log4J修改日志消息的一部分,我找不到任何好的来源。过滤器似乎更加有限,只能决定是否记录特定事件,但不能改变消息的内容。我还发现了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的情况、后端服务器屏蔽CID的情况或其他情况
  • 我使用了一个简单的正则表达式,因为我不担心误报
代码经过单元测试,因此我确信它工作正常。当然,如果您发现任何改进的可能性,请让我知道:-)

您可以编写自己的并为所有Appender配置它


Layout有一种格式化方法,可以从包含日志消息的loggingEvent生成一个字符串…

更好的信用卡号码屏蔽实现是在。
您希望记录发卡机构和校验和,而不是PAN(主帐号)。

您可以将新布局与您正在使用的现有布局组合:将与正则表达式不匹配的任何内容委托给它,然后删除或删除包含信用卡号的行。银行,这似乎是可行的。尽管在这种情况下,我更喜欢子类化而不是聚合。让我们对此进行一点实验……不确定为什么不让超级用户先将事件解析为字符串,然后再对其进行过滤。你们可以省下很多代码。谢谢你们-你们救了我的命@avok00,因为LoggingEvent是不可变的。PCI DSS 3.0允许最多显示BIN和最后四个BIN。当您有大量流量时,最好使用那些允许的最大参数进行屏蔽。这可以通过更改这两行来实现<代码>私有静态最终字符串掩码=“$1+3”
private static final Pattern=Pattern.compile(([0-9]{6})([0-9]{6,10})([0-9]{4})”好吧,更好是相对的:-)在这种情况下,我不想记录颁发者,也不想记录校验和。我对具体的卡号一点也不感兴趣——我们不需要在日志或任何东西中搜索它们。这就是为什么我也不在乎假阳性。唯一的一点是,没有完整的卡号会进入日志。但我同意,在其他情况下,亚当的解决方案可能更好。