我们使用正则表达式替换敏感数据,正则表达式中有5个组,例如:
/*
* {phoneNumber=(+358)0393289092389},
* then:
* (Group #1) (Group #2) (Group #3) (Group #4) (Group #5)
* { phoneNumber= (+358)0393289092389 }
*
* Group #1 Group #5
* ┌────────────────────────┐ ┌────────────────────────┐
* │ ┏━━━━━┓ │ │ ┏━━━━━┓ │
* │ ╭─┃ `[` ┃──────────╮ │ │ ╭─┃ `[` ┃──────────╮ │
* │ │ ┗━━━━━┛ │ │ │ │ ┗━━━━━┛ │ │
* │ │ ┏━━━━━┓ │ │ │ │ ┏━━━━━┓ │ │
* │ ├─┃ `]` ┃──────────┤ │ │ ├─┃ `]` ┃──────────┤ │
* │ │ ┗━━━━━┛ │ │ │ │ ┗━━━━━┛ │ │
* │ │ ┏━━━━━┓ │ │ │ │ ┏━━━━━┓ │ │
* │ ├─┃ `}` ┃──────────┤ │ │ ├─┃ `}` ┃──────────┤ │
* │ │ ┗━━━━━┛ │ │ │ │ ┗━━━━━┛ │ │
* │ │ ┏━━━━━┓ │ │ │ │ ┏━━━━━┓ │ │
* │ ├─┃ `{` ┃──────────┤ │ │ ├─┃ `{` ┃──────────┤ │
* │ │ ┗━━━━━┛ │ │ │ │ ┗━━━━━┛ │ │
* │ │ ┏━━━━━━━━━━━━━━┓ │ │ │ │ ┏━━━━━━━━━━━━━━┓ │ │
* │ ├─┃ `Begin with` ┃─┤ │ │ ├─┃ `Begin with` ┃─┤ │
* │ │ ┗━━━━━━━━━━━━━━┛ │ │ Group #2 Group #3 Group #4 │ │ ┗━━━━━━━━━━━━━━┛ │ │
* │ │ ┏━━━━━━━━━━━━┓ │ │ ┌──────────────────────────────────────────────────────────┐ ┌───────────────────┐ ┌─────────┐ │ │ ┏━━━━━━━━━━━━┓ │ │
* │ ├─┃ `End with` ┃───┤ │ │ One of │ │ One of │ │ │ │ ├─┃ `End with` ┃───┤ │
* │ │ ┗━━━━━━━━━━━━┛ │ │ │ ┏━━━━━━━┓ ┏━━━━━┓ ┏━━━━━┓ ┏━━━━━━━┓ ┏━━━━━┓ ┏━━━━━┓ │ │ ┏━━━━━━━━━━━━━━━┓ │ │ ┏━━━━━┓ │ │ │ ┗━━━━━━━━━━━━┛ │ │
* ?───┼──┤ ┏━━━━━━┓ ├──┼──┼─┃ `Key` ┃──┃ `"` ┃──┃ ` ` ┃──┃ `:|=` ┃──┃ ` ` ┃──┃ `"` ┃─┼──┼─┃ `_%\w@ .+)(-` ┃─┼──┼─┃ `"` ┃─┼──┼──┤ ┏━━━━━━┓ ├──┼───?
* │ ├─┃ `, ` ┃─────────┤ │ │ ┗━━━━━━━┛ ┗━━━━━┛ ┗━━━━━┛ ┗━━━━━━━┛ ┗━━━━━┛ ┗━━━━━┛ │ │ ┗━━━━━━━━━━━━━━━┛ │ │ ┗━━━━━┛ │ │ ├─┃ `, ` ┃─────────┤ │
* │ │ ┗━━━━━━┛ │ │ │ (0-1) (0-2) (0-2) (0-1) │ │ (1-∞) │ │ (0-1) │ │ │ ┗━━━━━━┛ │ │
* │ │ ┏━━━━━┓ │ │ └──────────────────────────────────────────────────────────┘ └───────────────────┘ └─────────┘ │ │ ┏━━━━━┓ │ │
* │ ├─┃ `,` ┃──────────┤ │ │ ├─┃ `,` ┃──────────┤ │
* │ │ ┗━━━━━┛ │ │ │ │ ┗━━━━━┛ │ │
* │ │ ┏━━━━━┓ │ │ │ │ ┏━━━━━┓ │ │
* │ ├─┃ ` ` ┃──────────┤ │ │ ├─┃ ` ` ┃──────────┤ │
* │ │ ┗━━━━━┛ │ │ │ │ ┗━━━━━┛ │ │
* │ │ ┏━━━━━┓ │ │ │ │ ┏━━━━━┓ │ │
* │ ├─┃ `;` ┃──────────┤ │ │ ├─┃ `;` ┃──────────┤ │
* │ │ ┗━━━━━┛ │ │ │ │ ┗━━━━━┛ │ │
* │ │ ┏━━━━━┓ │ │ │ │ ┏━━━━━┓ │ │
* │ ├─┃ `"` ┃──────────┤ │ │ ├─┃ `"` ┃──────────┤ │
* │ │ ┗━━━━━┛ │ │ │ │ ┗━━━━━┛ │ │
* │ │ ┏━━━━━┓ │ │ │ │ ┏━━━━━┓ │ │
* │ ╰─┃ `.` ┃──────────╯ │ │ ╰─┃ `.` ┃──────────╯ │
* │ ┗━━━━━┛ │ │ ┗━━━━━┛ │
* └────────────────────────┘ └────────────────────────┘
*
*/
首先还是继承logback的MessageConverter类,重写convert方法
public class SensitiveDataConverter extends MessageConverter
给一些参数做成了可配置的 ?
private final static String SENSITIVE_DEFAULT_DATA_KEYS = "fullName,firstName,lastName,middleName,address,ipAddress,nationalIdNumber,email,phoneNumber,mobile,birthDate,city,bankCard";
private final static String SENSITIVE_DATA_MASKING_ENABLED = "true";
private final static String SENSITIVE_DEFAULT_DATA_EXCLUSIONS = "INPUT_OUTPUT_MICROGAMING";
private final static String SENSITIVE_DEFAULT_DATA_DELIMITERS = "(\\[|\\]|\\}|\\{|^|$|, |,| |;|\"|\\.)";
private final static boolean maskEnabled;
private final static List<String> sensitiveDataKeys;
private final static List<String> sensitiveDataExclusionsKeys;
private final static List<String> regexList;
static {
String maskEnabledConfig = StringUtil.isEmptyString(System.getenv("SENSITIVE_DATA_MASKING_ENABLED")) ? SENSITIVE_DATA_MASKING_ENABLED : System.getenv("SENSITIVE_DATA_MASKING_ENABLED");
String sensitiveDataKeysConfig = StringUtil.isEmptyString(System.getenv("SENSITIVE_DATA_KEYS")) ? SENSITIVE_DEFAULT_DATA_KEYS : System.getenv("SENSITIVE_DATA_KEYS");
String sensitiveDataExclusionsKeysConfig = StringUtil.isEmptyString(System.getenv("SENSITIVE_DATA_EXCLUSIONS")) ? SENSITIVE_DEFAULT_DATA_EXCLUSIONS : System.getenv("SENSITIVE_DATA_EXCLUSIONS");
String Delimiters = StringUtil.isEmptyString(System.getenv("SENSITIVE_DATA_DELIMITERS")) ? SENSITIVE_DEFAULT_DATA_DELIMITERS : System.getenv("SENSITIVE_DATA_DELIMITERS");
maskEnabled = "true".equals(maskEnabledConfig);
sensitiveDataKeys = Arrays.asList(sensitiveDataKeysConfig.split(","));
sensitiveDataExclusionsKeys = Arrays.asList(sensitiveDataExclusionsKeysConfig.split(","));
regexList = sensitiveDataKeys.stream().map(key -> Delimiters + "(" + key + " {0,2}\"?[:|=]\"? {0,2})((?!null)[\\\\_%\\w@.+)(-]+)(\"?)" + Delimiters).collect(Collectors.toList());
}
@Override
public String convert(ILoggingEvent event) {
String logText = event.getFormattedMessage();
return filterSensitiveInformation(logText);
}
public static String filterSensitiveInformation(String logText) {
if (!maskEnabled || hasExclusion(logText)) {
return logText;
}
AtomicReference<String> maskedText = new AtomicReference<>(logText);
regexList.forEach(regex -> {
maskedText.set(maskedText.get().replaceAll(regex, "$1$2****$4$5"));
});
return maskedText.get();
}
private static boolean hasExclusion(String logText) {
return sensitiveDataExclusionsKeys.stream().anyMatch(logText::contains);
}
优点:对于短的log匹配很方便很快 缺点:对于特别长的log,regex匹配性能呈指数下降,非常影响服务器性能,建议斟酌使用。 ?
下期来细细讲解一下regex的匹配机制
|