Перейти к основному содержимому

Маскируйте конфиденциальные данные в журналах с помощью Logback

· 4 мин. чтения

1. Обзор

При большом объеме регистрируемых данных важно скрывать конфиденциальные сведения о пользователях при регистрации. В новом мире, нынешнем GDPR, помимо многих проблем, мы должны уделять особое внимание регистрации конфиденциальных данных отдельных лиц.

В этом руководстве мы увидим, как маскировать конфиденциальные данные в журналах с помощью Logback. В целом, этот подход не является реальным способом решения проблемы — это своего рода последняя линия защиты для наших лог-файлов.

2. Логбэк

Logback — одна из наиболее широко используемых сред ведения журналов в сообществе Java. Это замена своего предшественника Log4j. Он предлагает более быструю реализацию, чем Log4j, и предоставляет больше возможностей для настройки и большую гибкость в архивировании старых файлов журналов.

Конфиденциальные данные — это любая информация, которая должна быть защищена от несанкционированного доступа. Это может включать в себя что угодно, от личной информации (PII), такой как номера социального страхования, до банковской информации, учетных данных для входа, адреса, электронной почты и других.

Мы будем маскировать конфиденциальные данные, принадлежащие пользователям, при входе в наше приложение.

3. Маскировка данных

Допустим, мы регистрируем данные пользователя в контексте веб-запроса. Нам нужно замаскировать конфиденциальные данные, связанные с пользователями. Предположим, что наше приложение получает следующий запрос или ответ, который мы зарегистрировали:

{
"user_id":"87656",
"ssn":"786445563",
"address":"22 Street",
"city":"Chicago",
"Country":"U.S.",
"ip_address":"192.168.1.1",
"email_id":"spring@foreach.com"
}

Здесь мы видим, что у нас есть конфиденциальные данные, такие как ssn , address , ip_address и email_id . Следовательно, мы должны маскировать эти данные при регистрации.

Мы будем маскировать журналы централизованно, настроив правила маскирования для всех записей журнала, созданных Logback. Для этого нам нужно реализовать собственный ch.qos.logback.classic.PatternLayout .

3.1. ШаблонМакет

Идея конфигурации заключается в расширении каждого приложения Logback, которое нам нужно, с помощью пользовательского макета . В нашем случае мы напишем класс MaskingPatternLayout как реализацию PatternLayout. Каждый шаблон маски представляет собой регулярное выражение, соответствующее одному типу конфиденциальных данных.

Давайте создадим класс MaskingPatternLayout :

public class MaskingPatternLayout extends PatternLayout {

private Pattern multilinePattern;
private List<String> maskPatterns = new ArrayList<>();

public void addMaskPattern(String maskPattern) {
maskPatterns.add(maskPattern);
multilinePattern = Pattern.compile(maskPatterns.stream().collect(Collectors.joining("|")), Pattern.MULTILINE);
}

@Override
public String doLayout(ILoggingEvent event) {
return maskMessage(super.doLayout(event));
}

private String maskMessage(String message) {
if (multilinePattern == null) {
return message;
}
StringBuilder sb = new StringBuilder(message);
Matcher matcher = multilinePattern.matcher(sb);
while (matcher.find()) {
IntStream.rangeClosed(1, matcher.groupCount()).forEach(group -> {
if (matcher.group(group) != null) {
IntStream.range(matcher.start(group), matcher.end(group)).forEach(i -> sb.setCharAt(i, '*'));
}
});
}
return sb.toString();
}
}

Реализация PatternLayout . doLayout() отвечает за маскирование совпадающих данных в каждом сообщении журнала нашего приложения, если оно соответствует одному из настроенных шаблонов.

Список maskPatterns из logback.xml создает многострочный шаблон. К сожалению, движок Logback не поддерживает внедрение конструктора. Если это список свойств, addMaskPattern вызывается для каждой записи конфигурации. Таким образом, мы должны компилировать шаблон каждый раз, когда добавляем в список новое регулярное выражение.

3.2. Конфигурация

В общем, мы можем использовать шаблоны регулярных выражений для маскировки конфиденциальных сведений о пользователе .

Например, для SSN мы можем использовать регулярное выражение, например:

\"SSN\"\s*:\s*\"(.*)\"

А для адреса мы можем использовать:

\"address\"\s*:\s*\"(.*?)\" 

Кроме того, для шаблона данных IP-адреса (192.169.0.1) мы можем использовать регулярное выражение:

(\d+\.\d+\.\d+\.\d+)

Наконец, для электронной почты мы можем написать:

(\w+@\w+\.\w+)

Теперь мы добавим эти шаблоны регулярных выражений в теги maskPattern внутри нашего файла logback.xml :

<configuration>
<appender name="mask" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="com.foreach.logback.MaskingPatternLayout">
<maskPattern>\"SSN\"\s*:\s*\"(.*?)\"</maskPattern> <!-- SSN JSON pattern -->
<maskPattern>\"address\"\s*:\s*\"(.*?)\"</maskPattern> <!-- Address JSON pattern -->
<maskPattern>(\d+\.\d+\.\d+\.\d+)</maskPattern> <!-- Ip address IPv4 pattern -->
<maskPattern>(\w+@\w+\.\w+)</maskPattern> <!-- Email pattern -->
<pattern>%-5p [%d{ISO8601,UTC}] [%thread] %c: %m%n%rootException</pattern>
</layout>
</encoder>
</appender>
</ configuration>

3.3. Исполнение

Теперь мы создадим JSON для приведенного выше примера и используем logger.info() для регистрации деталей:

Map<String, String> user = new HashMap<String, String>();
user.put("user_id", "87656");
user.put("SSN", "786445563");
user.put("address", "22 Street");
user.put("city", "Chicago");
user.put("Country", "U.S.");
user.put("ip_address", "192.168.1.1");
user.put("email_id", "spring@foreach.com");
JSONObject userDetails = new JSONObject(user);

logger.info("User JSON: {}", userDetails);

После выполнения этого мы можем увидеть вывод:

INFO  [2021-06-01 16:04:12,059] [main] com.foreach.logback.MaskingPatternLayoutExample: User JSON: 
{"email_id":"*******************","address":"*********","user_id":"87656","city":"Chicago","Country":"U.S.", "ip_address":"***********","SSN":"*********"}

Здесь мы видим, что пользователь JSON в нашем регистраторе замаскирован:

{
"user_id":"87656",
"ssn":"*********",
"address":"*********",
"city":"Chicago",
"Country":"U.S.",
"ip_address":"*********",
"email_id":"*****************"
}

При таком подходе мы можем маскировать только те данные в файлах журналов, для которых мы определили регулярные выражения в maskPattern в logback.xml .

4. Вывод

В этом руководстве мы рассмотрели, как использовать функцию PatternLayout для маскировки конфиденциальных данных в журналах приложений с помощью Logback. Кроме того, мы увидели, как добавлять шаблоны регулярных выражений в logback.xml для маскировки определенных данных.

Как обычно, фрагменты кода доступны на GitHub .