logback 日志脱敏 隐藏PII信息
PII信息全称:Personally identifiable information (PII)
PII is any information about an individual maintained by an agency, including
any information that can be used to distinguish or trace an individual‘s identity, such as name, social security number, date and place of birth, mother‘s maiden name, or biometric records;
any other information that is linked or linkable to an individual, such as medical, educational, financial, and employment information.
Link:(https://piwik.pro/blog/what-is-pii-personal-data/)
大概翻译一下就是能够代表一个人身份的一些信息,包括但不限于姓名、社会安全号码、出生日期和地点、母亲的婚前姓氏或生物识别记录。
为了提高网络安全集成评估,需要在日志中屏蔽这些信息。
以下是具体实现:
利用logback的Converter,自定义日志格式转换符,然后继承ClassicConverter
首先定义类:SensitiveDataConverter 继承父类:MessageConverter
具体代码:
package eu.digient.sdk.util;import ch.qos.logback.classic.pattern.MessageConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;public class SensitiveDataConverter extends MessageConverter {private final static String SENSITIVE_DEFAULT_DATA_KEYS = "fullName,address,ipAddress,nationalIdNumber,email,phoneNumber,birthDate,country,city,bankCard";private final static String SENSITIVE_DATA_MASKING_ENABLED = "true";@Overridepublic String convert(ILoggingEvent event) {String originLogMsg = event.getFormattedMessage();return filterSensitiveInformation(originLogMsg);}public String filterSensitiveInformation(final String oriMsg) {String sensitiveDataMaskingEnabled = StringUtil.isEmptyString(System.getenv("SENSITIVE_DATA_MASKING_ENABLED")) ? SENSITIVE_DATA_MASKING_ENABLED : System.getenv("SENSITIVE_DATA_MASKING_ENABLED");String sensitiveDataKeys = StringUtil.isEmptyString(System.getenv("SENSITIVE_DATA_KEYS")) ? SENSITIVE_DEFAULT_DATA_KEYS : System.getenv("SENSITIVE_DATA_KEYS");String tempMsg = oriMsg;if ("true".equals(sensitiveDataMaskingEnabled)) {if (sensitiveDataKeys != null && sensitiveDataKeys.length() > 0) {String[] keysArray = sensitiveDataKeys.split(",");for (String key : keysArray) {int index = -1;do {index = tempMsg.indexOf(key, index + 1);if (index != -1 &&!Pattern.matches("[a-zA-Z0-9]", tempMsg.substring(index + key.length(), index + key.length() + 1)) &&(index == 0 || !Pattern.matches("[a-zA-Z0-9]", tempMsg.substring(index - 1, index)))) {int valueStart = getValueStartIndex(tempMsg, index + key.length());int valueEnd = getValueEndIndex(tempMsg, valueStart);String subStr = tempMsg.substring(valueStart, valueEnd);subStr = mask(subStr);tempMsg = tempMsg.substring(0, valueStart) + subStr + tempMsg.substring(valueEnd);}} while (index != -1);}}}return tempMsg;}/*** Get the index of the first character of sensitive information*/private int getValueStartIndex(String msg, int valueStart) {while (true) {if (valueStart == msg.length()) {break;}char ch = msg.charAt(valueStart);if (ch == ':' || ch == '=') {valueStart++;ch = msg.charAt(valueStart);if (ch == '"') {valueStart++;}break;} else {valueStart++;}}return valueStart;}/*** Get the index of the last character of sensitive information*/private int getValueEndIndex(String msg, int valueEnd) {while (true) {if (valueEnd == msg.length()) {break;}char ch = msg.charAt(valueEnd);if (ch == '"') {if (valueEnd + 1 == msg.length()) {break;}char nextCh = msg.charAt(valueEnd + 1);if (nextCh == ';' || nextCh == ',') {while (valueEnd > 0) {char preCh = msg.charAt(valueEnd - 1);if (preCh != '\\') {break;}valueEnd--;}break;} else {valueEnd++;}} else if (ch == ';' || ch == ',' || ch == '}') {break;} else {valueEnd++;}}return valueEnd;}/*** Mask sensitive information*/private String mask(String submsg) {if (StringUtils.isBlank(submsg)) {return "";}return StringUtils.rightPad(StringUtils.left(submsg, 0), StringUtils.length(submsg), "*");}
}
在logback.xml 文件中加入(一定要加在appender标签的前面,最好就加在configuration标签的第一行,不然不会正确加载)
<conversionRule conversionWord="msg" converterClass="eu.digient.sdk.util.SensitiveDataConverter"/>
converterClass写上你方法的路径
最后把几个test也放在这里:
package eu.digient.sdk.utilimport org.junit.Test
import static org.junit.Assert.assertEqualsclass SensitiveDataConverterTest {SensitiveDataConverter sensitiveDataConverter = new SensitiveDataConverter()@Testvoid sensitiveDataTest() {assertEquals 'fullName =*******', sensitiveDataConverter.filterSensitiveInformation('fullName = tester')assertEquals 'fullName :*******', sensitiveDataConverter.filterSensitiveInformation('fullName : tester')assertEquals 'fullName=******,address=********', sensitiveDataConverter.filterSensitiveInformation('fullName=tester,address=some-add')assertEquals 'fullName:******,address:********', sensitiveDataConverter.filterSensitiveInformation('fullName:tester,address:some-add')}@Testvoid sensitiveDataConverter_withNomal() {def originLogMsg = '{nationalIdNumber=f88898b2677e62f1ad54b9e330c0a27e, currency=EUR, email=some@cn.com, fullName=%E5%BE%90%E5%BD%A6%E5%A8%9C, birthDate=2021-08-31}'def result = '{nationalIdNumber=********************************, currency=EUR, email=***********, fullName=***************************, birthDate=**********}'assertEquals result, sensitiveDataConverter.filterSensitiveInformation(originLogMsg)}@Testvoid sensitiveDataConverter_withJsonFormat() {def originLogMsg = '{"reason":"success ","result":{"jobid":"JH2131171027170837443588J6","fullName":"Tom","bankCard":"6226430106137525","nationalIdNumber":"130333198901192762","phoneNumber":"13210141605"}'def result = '{"reason":"success ","result":{"jobid":"JH2131171027170837443588J6","fullName":"***","bankCard":"****************","nationalIdNumber":"******************","phoneNumber":"************}'assertEquals result, sensitiveDataConverter.filterSensitiveInformation(originLogMsg)}@Testvoid sensitiveDataConverter_withJsonFormat2() {def originLogMsg = '{"body":"{\\"fullName\\":Tom,\\"address\\":\\someAdd\\}"}'def result = '{"body":"{\\"fullName\\":***,\\"address\\":*********}"}'assertEquals result, sensitiveDataConverter.filterSensitiveInformation(originLogMsg)}@Testvoid sensitiveDataConverter_withSemicolon() {def originLogMsg = '{nationalIdNumber=f88898b2677e62f1ad54b9e330c0a27el; currency=EUR; email=some@cn.com; fullName=%E5%BE%90%E5%BD%A6%E5%A8%9C; birthDate=2021-08-31}'def result = '{nationalIdNumber=*********************************; currency=EUR; email=***********; fullName=***************************; birthDate=**********}'assertEquals result, sensitiveDataConverter.filterSensitiveInformation(originLogMsg)}@Testvoid sensitiveDataConverter_withMoreChar() {def originLogMsg = '{nationalIdNumberOne=f88898b2677e62f1ad54b9e330c0a27el; currency=EUR; emailId=some@cn.com; somefullName=%E5%BE%90%E5%BD%A6%E5%A8%9C; birthDate=2021-08-31}'def result = '{nationalIdNumberOne=f88898b2677e62f1ad54b9e330c0a27el; currency=EUR; emailId=some@cn.com; somefullName=%E5%BE%90%E5%BD%A6%E5%A8%9C; birthDate=**********}'assertEquals result, sensitiveDataConverter.filterSensitiveInformation(originLogMsg)}
}
logback 日志脱敏 隐藏PII信息相关推荐
- 注解方式实现logback日志脱敏
切入点 logback-spring.xml <appender name="CONSOLE" class="ch.qos.logback.core.Console ...
- logback实现日志脱敏
许多系统为了安全需要对敏感信息(如手机号.邮箱.姓名.身份证号.密码.卡号.住址等)的日志打印要求脱敏后才能输出,本文将结合个人经历及总结分享一种logback日志脱敏方式,log4j实现日志脱敏请移 ...
- logback - 自定义日志脱敏组件,一种不错的脱敏方案
前言 在我们书写代码的时候,会书写许多日志代码,但是有些敏感数据是需要进行安全脱敏处理的. 对于日志脱敏的方式有很多,常见的有①使用conversionRule标签,继承MessageConverte ...
- java 日志脱敏框架 sensitive,优雅的打印脱敏日志
问题 为了保证用户的信息安全,敏感信息需要脱敏. 项目开发过程中,每次处理敏感信息的日志问题感觉很麻烦,大部分都是用工具类单独处理,不利于以后统一管理,很不优雅. 于是,就写了一个基于 java 注解 ...
- 一起进阶一起拿高工资!Java开发进阶-log4j2日志脱敏原理分析
本文首发于公众号[看点代码再上班],欢迎关注,第一时间获取最新文章. 大家好,我是tin,这是我的第5篇原创文章 本文讲述在考虑对业务系统代码入侵最小的情况下实现日志脱敏的方案原理.文章很长,包括了日 ...
- 简易的第三方组件日志脱敏
简易的第三方组件日志脱敏 1.下载jar包并打入自己的本地仓库 2.依赖 3.日志依赖 4.脱敏规则-logback-desensitize.yml 5.logback.xml 6.applicati ...
- SpringBoot 日志脱敏,开源组件太强了!
在我们书写代码的时候,会书写许多日志代码,但是有些敏感数据是需要进行安全脱敏处理的. 对于日志脱敏的方式有很多,常见的有①使用conversionRule标签,继承MessageConverter②书 ...
- Log4j日志脱敏记录一下
前言 在项目上线环境中,需要记录程序运行时产生的各种错误信息.状态信息.调试信息.执行时间记录等日志信息.可以用于查找问题.定位数据等等操作. 日志的具体实现可以有log4j和logback等,这里我 ...
- Nginx隐藏主机信息,proxy_hide_header 与fastcgi_hide_header
Nginx中proxy_hide_header 与fastcgi_hide_header都可以隐藏主机头信息,两者在具体使用时还是有着一定的区别的.刚好业务使用的nginx反向代理在显示响应头时将后端 ...
最新文章
- FTP同步的另类解决办法——NetDrive
- Autodesk MapGuide Enterprise 2011 Update 1 for Windows发布了
- oracle中or的替函数,Oracle常用内置Or自定义函数-SQL宝典
- 【创业】创业公司股权架构设计注意事项
- virt-manager 使用 shh 远程访问配置方法
- ip_vs实现分析(2)
- 潘淳的苏州.NET俱乐部成立有感!附我的录音
- [转]关于Apple TV(take 2)及 iPhone 更新的相关内容
- 腾讯封杀linux/mac QQ
- C#之不得不上的网站。
- ConnectionRead (WrapperRead())Timeout expired
- linux中可以使用-af含义,关于Windows中的linux:AF_UNIX
- 快速理解旋转运动公式
- 2023计算机考研专业课参考书目(408)
- NTL密码算法开源库——大整数ZZ类(一)
- Js 实现颜色值转换_Js 实现十六进制颜色值和RGB颜色值转换整理
- 发现薪资被倒挂!跳槽还是等待?
- ue4 截图_记录一下UE4截图功能
- 独立站常用建站工具大盘点——附收款方式及优惠
- PPT的粘贴选项没有选项
热门文章
- 开关电源计算机仿真技术pdf,《开关电源仿真设计》PPT课件.ppt
- 谷歌施密特:中国人相当出色2025年将超美国成AI主导丨业界大佬财报频出【软件网每日新闻播报│第11-3期】
- python如何实现语音识别
- 计算机二级两个控件之间求偶,求,全国计算机等级考试二级java历年试题及答案合集,还有上机考试真题?...
- html 中的push方法,push方法怎么使用
- 怎么用python画螺旋_用Python tu绘制螺旋
- 3d编辑器的gizmo的缩放计算
- 校招选择题汇总【图形推理(1)】含答案解析
- Android P SELinux (三) 权限检查原理与调试
- Linux内核——cli()和sti()