日志脱敏功能

2024-06-03 16:04
文章标签 日志 功能 脱敏

本文主要是介绍日志脱敏功能,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

数据安全尤为重要,最为简单的防线就是防止重要信息(身份证、手机号、姓名等)明文显示,对此需要在数据库层、日志层等做好数据加解密。

思路

1、编写需加密的正则模板、加密字段
2、重写ch.qos.logback.classic.pattern.MessageConverter
3、编写日志框架,确认转换模板(本篇采用logback.xml)

看不明白的直接无脑复制代码,在logback-sensitive-rule.properties文件中加上你需要的脱敏的字段即可

实战

正则模板及加密字段

在resource目录下建立两个properties文件,logback-sensitive-def-rule 和 logback-sensitive-rule。前者logback-sensitive-def-rule 主要指定正则表达式和默认加密字段,可作为公共二方包供所有项目使用,logback-sensitive-rule主要用于定制化项目,对特别项目需要加密字段的做定制化。

logback-sensitive-def-rule

#mobile  \"mobile\"|\"telphone\"
# ??json
def_rule1=(KEYWORD)(\\s{0,})(:)(\\s{0,})(\\\\"|\")(\\w{3})(\\w{4})(\\w{4})*(\\\\"|\")&$1$2$3$4$5$6****$8$9&mobile
# ??toString
def_rule_sec11=(KEYWORD)(\\s{0,})(:|=)(\\s{0,})(\"|\'|)(\\w{3})(\\w{4})(\\w{4})*(\"|\'|)&$1$2$3$4$5$6****$8$9&mobile
def_rule_sec12=(KEYWORD)(\\\\{0,}\\\"\\s{0,})(:)(\\s{0,})(\\\\{0,}\\\")(\\w{3})(\\w{4})(\\w{4})*(\\\\{0,}\\\")&$1$2$3$4$5$6****$8$9&mobile
def_field_rule_mobile=mobile|telphone#idcard,bankcard
def_rule2=(KEYWORD)(\\s{0,})(:)(\\s{0,})(\\\\"|\")(\\w{3})(\\w{1,})(\\w{4})(\\\\"|\")&$1$2$3$4$5$6*********$8$9&idcard
def_rule_sec21=(KEYWORD)(\\s{0,})(:|=)(\\s{0,})(\"|\'|)(\\w{3})(\\w{1,})(\\w{4})(\"|\'|)&$1$2$3$4$5$6*********$8$9&idcard
def_rule_sec22=(KEYWORD)(\\\\{0,}\\\"\\s{0,})(:)(\\\\{0,}\\s{0,})(\")(\\w{3})(\\w{1,})(\\w{4})(\\\\{0,}\\s{0,})(\")&$1$2$3$4$5$6******$8$9$10&idcard
def_field_rule_idcard=idcard|bankcard|idNo#pwd ("pwd")(\s{0,})(:|=)(\s{0,})(\\"|")(.*?)(\\"|")
def_rule3=(KEYWORD)(\\s{0,})(:)(\\s{0,})(\\\\"|\")(.*?)(\\\\"|\")&$1$2$3$4$5*****$7&pwd
def_rule_sec31=(KEYWORD)(\\s{0,})(:|=)(\\s{0,})(\"|)(.*?)(\"|,|\\)|])&$1$2$3$4$5*****$7&pwd
# def_rule_sec32=(KEYWORD)(,)(.*?)&$1$2*****&pwd
def_field_rule_pwd=password|pwd#username
# ??json
def_rule4=(KEYWORD)(\\s{0,})(:)(\\s{0,})(\\\\"|\")([\u4E00-\u9FA5]{1})[\u4E00-\u9FA5]{1,}(\\\\"|\")&$1$2$3$4$5$6**$7&name
# ??toString
def_rule_sec41=(KEYWORD)(\\s{0,})(:|=)(\\s{0,})(\"|\'|)([\u4E00-\u9FA5]{1})([\u4E00-\u9FA5]{1,})(\"|\'|)&$1$2$3$4$5$6**$8&name
# ????json???
def_rule_sec42=(KEYWORD)(\\\\{0,}\\\"\\s{0,})(:)(\\\\{0,}\\s{0,})(\\\")([\u4E00-\u9FA5]{1})([\u4E00-\u9FA5]{1,})(\\\\{0,}\\\")&$1$2$3$4$5$6**$8&name
def_field_rule_name=customerName|userName|name|custName#email
def_rule5=(KEYWORD)(\\s{0,})(:)(\\s{0,})(\\\\"|\")([A-Za-z0-9\u4e00-\u9fa5|_-]{1,2})([A-Za-z0-9\u4e00-\u9fa5|_-]{1,})@([a-z0-9A-Z_-]{2,})+(\\.[a-zA-Z0-9_-]{1,})(\\\\"|\")&$1$2$3$4$5$6***@$8$9$10&email
def_rule_sec51=(KEYWORD)(\\s{0,})(:|=)(\\s{0,})(\"|\'|)([A-Za-z0-9\u4e00-\u9fa5|_-]{1,2})([A-Za-z0-9\u4e00-\u9fa5|_-]{1,})@([a-z0-9A-Z_-]{2,})+(\\.[a-zA-Z0-9_-]{1,})(\"|\'|)&$1$2$3$4$5$6***@$8$9&email
def_field_rule_email=email#address
def_rule6=
# 未知长度,且未知数据格式
def_rule_sec61=(KEYWORD)(\\s{0,})(:|=)(\\s{0,})(\"|\')([\\u4E00-\\u9FA5]{0,}?\\S{0,}?)(\\S{0,10})(\"|\')&$1$2$3$4$5$6*****$8&address
def_rule_sec62=(KEYWORD)(\\\\{0,}\\\"\\s{0,})(:)(\\\\{0,}\\s{0,})(\\\")([\\u4E00-\\u9FA5]{0,}?\\S{0,}?)(\\S{0,10})(\\\\{0,}\\\")&$1$2$3$4$5$6*****$8&address
def_field_rule_address=address|idAddress

logback-sensitive-rule

# 定制化字段 分别代表 电话、姓名、证件号、地址
sen_field_rule_mobile=mobile|custMobileNo|bankPhone|mobileNo|reserveMobileNo|phone|contactPhone|accountPhone|custMobile|bankMobile
sen_field_rule_name=custName|acctName|openCustName|OCRname|name|accountName|dbAcctName|bankAcctName
sen_field_rule_idcard=idNo|acct|bankCardNo|ocrPrcid|certNo|dbAcct|id|originValue|idCardNo
sen_field_rule_address=custAddress|address|idAddress|entAddress|certAddress|ocrIdAddress
LogBackSensitiveConverter

重新ch.qos.logback.classic.pattern.MessageConverter的convert方法,主要实现思路是约定号规则字段(如sen_field_rule_、def_field_rule_),从properties文件中读取配置。

LogBackSensitiveConverter


import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.pattern.MessageConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Pattern;/*** 敏感信息脱敏处理**/
public class LogBackSensitiveConverter extends MessageConverter {private static Logger log = LoggerFactory.getLogger(LogBackSensitiveConverter.class);private static final String SEN_RULE = "sen_rule_";private static final String SEN_RULE_FIELD = "sen_field_rule_";private static final String DEFAULT_RULE = "def_rule";private static final String DEFAULT_RULE_FIELD = "def_field_rule_";/** 脱敏规则 */private static volatile List<RuleConfig> configList;/** 是否脱敏开关 */private static volatile boolean sensitiveOpen;/** 是否初始化配置 */private static volatile boolean initFlag;@Overridepublic String convert(ILoggingEvent event) {init();return doConvert(event);}private void init() {try {if (!initFlag) {initFlag = true;Map<String, String> propertyMap = ((LoggerContext) LoggerFactory.getILoggerFactory()).getCopyOfPropertyMap();sensitiveOpen = Boolean.valueOf(propertyMap.get("sensitiveOpen"));if (sensitiveOpen) {initRuleConfig(propertyMap);}}} catch (Exception e) {configList = null;log.error("error,{}", e);}}private String doConvert(ILoggingEvent event) {try {//本工具打日志不做转换if (LogBackSensitiveConverter.class.getName().equals(event.getLoggerName())) {return event.getFormattedMessage();}String result = event.getFormattedMessage();if (configList != null && configList.size() > 0) {for (RuleConfig ruleConfig : configList) {result = ruleConfig.apply(result);}if (StringUtils.isEmpty(result)) {result = event.getFormattedMessage();}} else {result = super.convert(event);}return result;} catch (Exception e) {log.error("error,{}", e);return event.getFormattedMessage();}}private void initRuleConfig(Map<String, String> propertyMap) {if (configList == null) {synchronized (LogBackSensitiveConverter.class) {if (configList == null) {// read propertiesPropertiesUtil propertiesUtil = new PropertiesUtil("logback-sensitive-def-rule.properties");Properties properties = propertiesUtil.get();configList = new ArrayList<>();//添加默认表达式addDefaultRule(propertyMap, properties);//添加自定义正则表达式addCustomRule(propertyMap);//                    this.addInfo("logback sensitive rule init end ! ");log.info("logback_sensitive_rule_init_end !");}}}}private void addCustomRule(Map<String, String> propertyMap) {for (String s : propertyMap.keySet()) {if (s.startsWith(SEN_RULE)) {String[] array = propertyMap.get(s).split("&");if (ArrayUtils.isNotEmpty(array) && array.length == 2) {configList.add(new RuleConfig(array[0], array[1]));}}}}private void addDefaultRule(Map<String, String> propertyMap, Properties properties) {for (String key : properties.stringPropertyNames()) {if (!key.startsWith(DEFAULT_RULE)) {continue;}String[] array = properties.getProperty(key).split("&");if (ArrayUtils.isNotEmpty(array) && array.length == 3) {//读默认字段String defFields = String.valueOf(properties.get(DEFAULT_RULE_FIELD + array[2]));//读自定义字段String senFields = propertyMap.get(SEN_RULE_FIELD + array[2]);String keyword = StringUtils.EMPTY;if (key.indexOf("sec") != -1) {senFields = StringUtils.isEmpty(senFields) ? "" : "|" + senFields;keyword = defFields + senFields;} else {keyword = "\"" + defFields.replace("|", "\"|\"") + "\"";if (!StringUtils.isEmpty(senFields)) {keyword += "|" + "\"" + senFields.replace("|", "\"|\"") + "\"";}keyword += "|\\\\\"" + defFields.replace("|", "\\\\\"|\\\\\"") + "\\\\\"";if (!StringUtils.isEmpty(senFields)) {keyword += "|\\\\\"" + senFields.replace("|", "\\\\\"|\\\\\"") + "\\\\\"";}}if (StringUtils.isEmpty(keyword)) {continue;}configList.add(new RuleConfig(array[0].replace("KEYWORD", keyword), array[1]));}}}private class RuleConfig {private String reg;private String replacement;private Pattern pattern;RuleConfig(String reg, String replacement) {this.reg = reg;this.replacement = replacement;this.pattern = Pattern.compile(reg);}public String getReg() {return reg;}public void setReg(String reg) {this.reg = reg;}public String getReplacement() {return replacement;}public void setReplacement(String replacement) {this.replacement = replacement;}public Pattern getPattern() {return pattern;}public void setPattern(Pattern pattern) {this.pattern = pattern;}String apply(String message) {if (StringUtils.isEmpty(message)) {return message;}return this.pattern.matcher(message).replaceAll(replacement);}}
}

PropertiesUtil


import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Properties;/*** Created by rayfoo@qq.com Luna on 2020/4/15 18:38* Description : 读取配置文件工具类*/
public class PropertiesUtil {private static Logger log = LoggerFactory.getLogger(PropertiesUtil.class);private Properties properties;public PropertiesUtil(String fileName) {if (StringUtils.isBlank(fileName)) {return;}properties = new Properties();try {properties.load(new InputStreamReader(PropertiesUtil.class.getClassLoader().getResourceAsStream(fileName)));} catch (IOException e) {log.error("PropertiesUtil load data error :{}", e);return;}}public Properties get() {return this.properties;}public String getProperty(String key) {String value = properties.getProperty(key.trim());if (StringUtils.isBlank(value)) {return null;}return value.trim();}public String getProperty(String key, String defaultValue) {String value = properties.getProperty(key);if (StringUtils.isBlank(value)) {return defaultValue;}return value;}}
配置logback,xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration><!--     脱敏开启开关 必须配置--><property scope="context" name="sensitiveOpen" value="true"/><!--    自定义属性配置文件:可自定义字段名和匹配正则表达式  可选配置--><property scope="context" resource="logback-sensitive-rule.properties"/><!--    转换配置 必选配置--><conversionRule conversionWord="msg" converterClass="com.xxx.xxx.xx.LogBackSensitiveConverter"> </conversionRule>
</configuration>

这篇关于日志脱敏功能的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1027458

相关文章

使用EasyPoi快速导出Word文档功能的实现步骤

《使用EasyPoi快速导出Word文档功能的实现步骤》EasyPoi是一个基于ApachePOI的开源Java工具库,旨在简化Excel和Word文档的操作,本文将详细介绍如何使用EasyPoi快速... 目录一、准备工作1、引入依赖二、准备好一个word模版文件三、编写导出方法的工具类四、在Export

JS纯前端实现浏览器语音播报、朗读功能的完整代码

《JS纯前端实现浏览器语音播报、朗读功能的完整代码》在现代互联网的发展中,语音技术正逐渐成为改变用户体验的重要一环,下面:本文主要介绍JS纯前端实现浏览器语音播报、朗读功能的相关资料,文中通过代码... 目录一、朗读单条文本:① 语音自选参数,按钮控制语音:② 效果图:二、朗读多条文本:① 语音有默认值:②

C#实现高性能拍照与水印添加功能完整方案

《C#实现高性能拍照与水印添加功能完整方案》在工业检测、质量追溯等应用场景中,经常需要对产品进行拍照并添加相关信息水印,本文将详细介绍如何使用C#实现一个高性能的拍照和水印添加功能,包含完整的代码实现... 目录1. 概述2. 功能架构设计3. 核心代码实现python3.1 主拍照方法3.2 安全HBIT

Java 日志中 Marker 的使用示例详解

《Java日志中Marker的使用示例详解》Marker是SLF4J(以及Logback、Log4j2)提供的一个接口,它本质上是一个命名对象,你可以把它想象成一个可以附加到日志语句上的标签或戳... 目录什么是Marker?为什么使用Markejavascriptr?1. 精细化的过滤2. 触发特定操作3

linux查找java项目日志查找报错信息方式

《linux查找java项目日志查找报错信息方式》日志查找定位步骤:进入项目,用tail-f实时跟踪日志,tail-n1000查看末尾1000行,grep搜索关键词或时间,vim内精准查找并高亮定位,... 目录日志查找定位在当前文件里找到报错消息总结日志查找定位1.cd 进入项目2.正常日志 和错误日

录音功能在哪里? 电脑手机等设备打开录音功能的技巧

《录音功能在哪里?电脑手机等设备打开录音功能的技巧》很多时候我们需要使用录音功能,电脑和手机这些常用设备怎么使用录音功能呢?下面我们就来看看详细的教程... 我们在会议讨论、采访记录、课堂学习、灵感创作、法律取证、重要对话时,都可能有录音需求,便于留存关键信息。下面分享一下如何在电脑端和手机端上找到录音功能

Android实现图片浏览功能的示例详解(附带源码)

《Android实现图片浏览功能的示例详解(附带源码)》在许多应用中,都需要展示图片并支持用户进行浏览,本文主要为大家介绍了如何通过Android实现图片浏览功能,感兴趣的小伙伴可以跟随小编一起学习一... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

Python使用FastAPI实现大文件分片上传与断点续传功能

《Python使用FastAPI实现大文件分片上传与断点续传功能》大文件直传常遇到超时、网络抖动失败、失败后只能重传的问题,分片上传+断点续传可以把大文件拆成若干小块逐个上传,并在中断后从已完成分片继... 目录一、接口设计二、服务端实现(FastAPI)2.1 运行环境2.2 目录结构建议2.3 serv

SpringBoot日志级别与日志分组详解

《SpringBoot日志级别与日志分组详解》文章介绍了日志级别(ALL至OFF)及其作用,说明SpringBoot默认日志级别为INFO,可通过application.properties调整全局或... 目录日志级别1、级别内容2、调整日志级别调整默认日志级别调整指定类的日志级别项目开发过程中,利用日志

Debian 13升级后网络转发等功能异常怎么办? 并非错误而是管理机制变更

《Debian13升级后网络转发等功能异常怎么办?并非错误而是管理机制变更》很多朋友反馈,更新到Debian13后网络转发等功能异常,这并非BUG而是Debian13Trixie调整... 日前 Debian 13 Trixie 发布后已经有众多网友升级到新版本,只不过升级后发现某些功能存在异常,例如网络转