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

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

正则表达式部分不是问题,我将重用我们已在其他几个地方使用的正则表达式。 但是我找不到有关如何使用Log4J更改日志消息的一部分的任何好的来源。 filter似乎更受限制,只能决定是否记录特定事件,但不能改变消息的内容。 我还发现了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被此记录器屏蔽的情况,以及后端服务器完成的情况,或者其他任何情况
  • 我使用简单的正则表达式,因为我并不担心误报

代码是经过unit testing的,所以我相信它能正常工作。 当然,如果你发现任何改进它的可能性,请告诉我:-)

您可以编写自己的布局并为所有appender配置它……

Layout有一个格式方法,它从包含日志消息的loggingEvent生成一个String …

有关信用卡号码屏蔽的更好实施方法,请访问http://adamcaudill.com/2011/10/20/masking-credit-cards-for-pci/ 。 您想记录发行者和校验和,但不记录PAN(主帐号)。