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

2022-09-01 14:42:53

我们的网络应用程序需要符合PCI标准,即它不得存储任何信用卡号。该应用程序是大型机系统的前端,该系统在内部处理CC编号,并且 - 正如我们刚刚发现的那样 - 偶尔还会在其响应屏幕上吐出完整的CC编号。默认情况下,这些响应的全部内容记录在调试级别,并且从这些响应解析的内容也可以记录在许多不同的位置。因此,我无法追查此类数据泄漏的来源。我必须确保CC号码在我们的日志文件中被屏蔽。

正则表达式部分不是问题,我将重用我们已经在其他几个地方使用的正则表达式。但是,我只是找不到有关如何使用Log4J更改部分日志消息的良好来源。过滤器似乎受到更多限制,只能决定是否记录特定事件,但不能更改消息的内容。我还找到了用于Log4J的ESAPI安全包装器API,乍一看,它承诺做我想做的事。但是,显然我需要将代码中的所有记录器替换为ESAPI记录器类 - 屁股很痛。我更喜欢一个更透明的解决方案。

任何想法如何从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 被此记录器屏蔽的情况、后端服务器或其他任何人完成的情况+*
  • 我使用一个简单的正则表达式,因为我不担心误报

代码经过单元测试,所以我相当确信它可以正常工作。当然,如果您发现任何改进它的可能性,请让我知道:-)


答案 1

您可以编写自己的布局并为其配置所有附加器...

布局有一个格式方法,该方法使字符串来自包含日志记录消息的事件...


答案 2

信用卡号屏蔽的更好实现是在 http://adamcaudill.com/2011/10/20/masking-credit-cards-for-pci/ 。您希望记录颁发者和校验和,但不希望记录 PAN(主帐号)。


推荐