步骤说明:
1) 利用 SM2 生成加解密密钥对(点击查看网友的SM2工具类)
2)约定日志打印格式,方便写正则去匹配需要加密/脱敏的日志信息
3)新建类继承Logback的MessageConvert类,重写其convert方法,通过正则去匹配待加密日志
4)对匹配到的日志内容使用SM2的加密函数对日志内容做加密处理。
实现示例(此处代码省略了SM2工具类的实现,点击查看-SM2Util实现):
import ch.qos.logback.classic.pattern.MessageConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.crypto.engines.SM2Engine;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
...
/**
* @author leon
* @date 2022/7/20
* @description 日志中敏感数据加密/脱敏
*
*/
@Slf4j
public class SensitiveLogDataConverter extends MessageConverter {
/** 公钥 */
private static final String PUBLIC_KEY = "公钥";
/** 私钥 */
private static final String PRIVATE_KEY = "私钥";
/** 需要加密的出入参日志匹配正则 */
public static final String ENCRYPT_LOG_REGEX = "(?<=[出,入]参=\\{).*?(?=\\}$)";
/** 手机号正则(可能滞后) */
// private static final String PHONE_REGEX = "(\\+861[3|4|5|6|7|8|9][0-9]\\d{8}[^\\d])|(^1[3|4|5|6|7|8|9][0-9]\\d{8})[^\\d]|([^\\d]1[3|4|5|6|7|8|9][0-9]\\d{8}[^\\d])";
/** 身份证正则(可能滞后)*/
// private static final String ID_CARD_REGEX = "[^\\d]([1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx])[^\\d]|[^\\d](^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3})[^\\d]";
/** 邮箱正则(可能滞后) **/
// private static final String EMAIL_REGEX = "[a-zA-Z]([a-zA-Z]|[.])*@[a-zA-Z]+([.][a-zA-Z]+)+";
@Override
public String convert(ILoggingEvent event) {
// 获取原始日志
String requestLogMsg = event.getFormattedMessage();
// 对敏感信息处理后返回
return handleSensitive(requestLogMsg);
}
/**
* 对敏感信息处理
*/
private static String handleSensitive(String content) {
try {
if (StringUtils.isBlank(content)) {
return content;
}
content = encryptLog(content);
// 还可进行其他日志处理,比如可以指定要处理的用户姓名,手机号,身份证号等
return content;
} catch (Exception e) {
return content;
}
}
/**
* 对出入参日志做加密处理
* @param hisLog
* @return
*/
private static String encryptLog(String logInfo) {
Pattern pattern = Pattern.compile(ENCRYPT_LOG_REGEX);
Matcher matcher = pattern.matcher(logInfo);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
matcher.appendReplacement(sb, encryption(matcher.group()));
}
matcher.appendTail(sb);
return sb.toString();
}
// 你的SM2 加密处理实现
private static String encryption(String plain) {
SM2 sm2 = SmUtil.sm2(PRIVATE_KEY, PUBLIC_KEY);
sm2.setMode(SM2Engine.Mode.C1C2C3);
byte[] encrypt = sm2.encrypt(plain.getBytes(StandardCharsets.UTF_8), KeyType.PublicKey);
return HexUtil.byteToHex(encrypt);
}
// 你的SM2 解密处理实现
private static String decryption(String enc) {
SM2 sm2 = SmUtil.sm2(PRIVATE_KEY, PUBLIC_KEY);
sm2.setMode(SM2Engine.Mode.C1C2C3);
byte[] decryptBytes = sm2.decrypt(HexUtil.decodeHex(enc), KeyType.PrivateKey);
return StrUtil.str(decryptBytes, StandardCharsets.UTF_8);
}
// 测试方法
public static void main(String[] args) {
// 填充加密信息
log.info("解密:" + decryption("密文"));
}