Наше веб-приложение должно быть совместимым с PCI, т. Е. Оно не должно хранить номера кредитных карт. Приложение является интерфейсом к системе мэйнфреймов, которая обрабатывает номера CC внутри и, как мы только что выяснили, время от времени все еще выдает полный номер CC на одном из своих экранов ответов. По умолчанию все содержимое этих ответов регистрируется на уровне отладки, а также анализируемое из них содержимое может регистрироваться в разных местах. Поэтому я не могу выследить источник таких утечек данных. Я должен убедиться, что номера CC замаскированы в наших файлах журнала.
Регулярное выражение не является проблемой, я буду использовать регулярное выражение, которое мы уже используем, в нескольких других местах. Однако я просто не могу найти хороший источник о том, как изменить часть сообщения журнала с Log4J. Фильтры, по-видимому, гораздо более ограничены, они могут только решить, регистрировать ли конкретное событие или нет, но не могут изменить содержание сообщения. Я также нашел API оболочки безопасности ESAPI для Log4J, который на первый взгляд обещает делать то, что я хочу. Тем не менее, по-видимому, мне нужно будет заменить все регистраторы в коде на класс регистратора 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 был замаскирован этим регистратором, от случаев, когда это было сделано внутренним сервером или кем-либо еще
- Я использую упрощенное регулярное выражение, потому что я не беспокоюсь о ложных срабатываниях
Код проверен модульно, поэтому я уверен, что он работает правильно. Конечно, если вы обнаружите какую-либо возможность улучшить его, пожалуйста, дайте мне знать: -)