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

发布于 2024-08-25 15:22:43 字数 1976 浏览 8 评论 0原文

我们的 Web 应用程序需要符合 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 被此记录器屏蔽的情况、由后端服务器或其他我使用简单化方法 正则表达式,因为我不担心误报

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

Our web app needs to be made PCI compliant, i.e. it must not store any credit card numbers. The app is a frontend to a mainframe system which handles the CC numbers internally and - as we have just found out - occasionally still spits out a full CC number on one of its response screens. By default, the whole content of these responses are logged at debug level, and also the content parsed from these can be logged in lots of different places. So I can't hunt down the source of such data leaks. I must make sure that CC numbers are masked in our log files.

The regex part is not an issue, I will reuse the regex we already use in several other places. However I just can't find any good source on how to alter a part of a log message with Log4J. Filters seem to be much more limited, only able to decide whether to log a particular event or not, but can't alter the content of the message. I also found the ESAPI security wrapper API for Log4J which at first sight promises to do what I want. However, apparently I would need to replace all the loggers in the code with the ESAPI logger class - a pain in the butt. I would prefer a more transparent solution.

Any idea how to mask out credit card numbers from Log4J output?

Update: Based on @pgras's original idea, here is a working solution:

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);
    }
}

Notes:

  • I mask with + rather than *, because I want to tell apart cases when the CID was masked by this logger, from cases when it was done by the backend server, or whoever else
  • I use a simplistic regex because I am not worried about false positives

The code is unit tested so I am fairly convinced it works properly. Of course, if you spot any possibility to improve it, please let me know :-)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夜司空 2024-09-01 15:22:43

您可以编写自己的 布局 并为所有附加程序配置它...

布局有一个格式方法,它从包含日志消息的loggingEvent中创建一个字符串...

You could write your own layout and configure it for all appenders...

Layout has a format method which makes a String from a loggingEvent that contains the logging message...

凉月流沐 2024-09-01 15:22:43

信用卡号屏蔽的更好实现位于 http:// adamcaudill.com/2011/10/20/masking-credit-cards-for-pci/
您想要记录发卡机构和校验和,但不记录 PAN(主帐号)。

A better implementation of credit card number masking is at http://adamcaudill.com/2011/10/20/masking-credit-cards-for-pci/ .
You want to log the issuer and the checksum, but not the PAN (Primary Account Number).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文