news 2026/4/12 11:43:22

生产环境日志脱敏方案:保护用户隐私数据

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
生产环境日志脱敏方案:保护用户隐私数据

被安全部门约谈了一次。

原因是日志里明文打印了用户手机号、身份证号,还被导出到了测试环境。这要是出了事,GDPR罚款能让公司破产。

花了两周时间做日志脱敏,整理一下方案。

为什么要日志脱敏

日志里经常会有:

  • 手机号、身份证号
  • 银行卡号、密码(别笑,真有人打印)
  • 地址、邮箱
  • Token、API Key

这些数据如果:

  • 被运维人员看到 → 内部泄露风险
  • 日志被导出 → 外部泄露风险
  • 日志被攻击者获取 → 直接完蛋

方案一:代码层脱敏

最可控的方式,在打日志的地方处理。

1.1 自定义toString

publicclassUser{privateStringname;privateStringphone;privateStringidCard;@OverridepublicStringtoString(){return"User{"+"name='"+maskName(name)+'\''+", phone='"+maskPhone(phone)+'\''+", idCard='"+maskIdCard(idCard)+'\''+'}';}privateStringmaskPhone(Stringphone){if(phone==null||phone.length()!=11)returnphone;returnphone.substring(0,3)+"****"+phone.substring(7);}privateStringmaskIdCard(StringidCard){if(idCard==null||idCard.length()<10)returnidCard;returnidCard.substring(0,4)+"**********"+idCard.substring(idCard.length()-4);}privateStringmaskName(Stringname){if(name==null||name.length()<2)returnname;returnname.charAt(0)+"*".repeat(name.length()-1);}}

打印出来:

User{name='张*', phone='138****5678', idCard='3201**********1234'}

1.2 注解方式

更优雅一点,用注解标记敏感字段:

// 自定义注解@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public@interfaceSensitive{SensitiveTypetype();}publicenumSensitiveType{PHONE,ID_CARD,NAME,BANK_CARD,EMAIL}// 使用注解publicclassUser{@Sensitive(type=SensitiveType.NAME)privateStringname;@Sensitive(type=SensitiveType.PHONE)privateStringphone;@Sensitive(type=SensitiveType.ID_CARD)privateStringidCard;}
// 脱敏工具类publicclassSensitiveUtil{publicstaticStringmask(Objectobj){if(obj==null)return"null";Class<?>clazz=obj.getClass();StringBuildersb=newStringBuilder(clazz.getSimpleName()+"{");Field[]fields=clazz.getDeclaredFields();for(inti=0;i<fields.length;i++){Fieldfield=fields[i];field.setAccessible(true);Stringvalue;try{ObjectfieldValue=field.get(obj);if(field.isAnnotationPresent(Sensitive.class)){Sensitiveannotation=field.getAnnotation(Sensitive.class);value=doMask(String.valueOf(fieldValue),annotation.type());}else{value=String.valueOf(fieldValue);}}catch(IllegalAccessExceptione){value="N/A";}sb.append(field.getName()).append("='").append(value).append("'");if(i<fields.length-1)sb.append(", ");}returnsb.append("}").toString();}privatestaticStringdoMask(Stringvalue,SensitiveTypetype){if(value==null||"null".equals(value))returnvalue;switch(type){casePHONE:returnvalue.length()==11?value.substring(0,3)+"****"+value.substring(7):value;caseID_CARD:returnvalue.length()>=10?value.substring(0,4)+"**********"+value.substring(value.length()-4):value;caseNAME:returnvalue.length()>=2?value.charAt(0)+"*".repeat(value.length()-1):value;caseBANK_CARD:returnvalue.length()>=8?value.substring(0,4)+"****"+value.substring(value.length()-4):value;caseEMAIL:intatIndex=value.indexOf("@");returnatIndex>2?value.substring(0,2)+"***"+value.substring(atIndex):value;default:returnvalue;}}}

使用:

log.info("用户信息: {}",SensitiveUtil.mask(user));// 输出:用户信息: User{name='张*', phone='138****5678', idCard='3201**********1234'}

方案二:日志框架层脱敏

在Logback/Log4j2层面统一处理。

2.1 Logback自定义Converter

publicclassSensitivePatternConverterextendsClassicConverter{privatestaticfinalPatternPHONE_PATTERN=Pattern.compile("1[3-9]\\d{9}");privatestaticfinalPatternIDCARD_PATTERN=Pattern.compile("\\d{17}[\\dXx]");privatestaticfinalPatternEMAIL_PATTERN=Pattern.compile("[\\w.]+@[\\w.]+");@OverridepublicStringconvert(ILoggingEventevent){Stringmessage=event.getFormattedMessage();// 手机号脱敏message=PHONE_PATTERN.matcher(message).replaceAll(m->m.group().substring(0,3)+"****"+m.group().substring(7));// 身份证脱敏message=IDCARD_PATTERN.matcher(message).replaceAll(m->m.group().substring(0,4)+"**********"+m.group().substring(14));// 邮箱脱敏message=EMAIL_PATTERN.matcher(message).replaceAll(m->{Stringemail=m.group();intatIndex=email.indexOf("@");returnatIndex>2?email.substring(0,2)+"***"+email.substring(atIndex):email;});returnmessage;}}
<!-- logback.xml --><configuration><conversionRuleconversionWord="sensMsg"converterClass="com.example.SensitivePatternConverter"/><appendername="CONSOLE"class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger - %sensMsg%n</pattern></encoder></appender></configuration>

这样所有日志自动脱敏,无需改业务代码。

2.2 Log4j2 RewritePolicy

@Plugin(name="SensitiveRewritePolicy",category="Core",elementType="rewritePolicy")publicclassSensitiveRewritePolicyimplementsRewritePolicy{@OverridepublicLogEventrewrite(LogEventevent){Messagemessage=event.getMessage();StringformattedMessage=message.getFormattedMessage();// 脱敏处理StringmaskedMessage=maskSensitiveData(formattedMessage);returnnewLog4jLogEvent.Builder(event).setMessage(newSimpleMessage(maskedMessage)).build();}privateStringmaskSensitiveData(Stringmessage){// 同上,正则替换returnmessage;}}

方案三:日志采集层脱敏

在Logstash/Filebeat采集时处理。

3.1 Logstash Filter

filter{# 手机号脱敏mutate{gsub=>["message","1[3-9]\d{9}","1**********"]}# 身份证脱敏mutate{gsub=>["message","\d{17}[\dXx]","****"]}# 银行卡脱敏mutate{gsub=>["message","\d{16,19}","****"]}}

3.2 Filebeat Processor

processors:-script:lang:javascriptsource:>function process(event) { var message = event.Get("message"); // 手机号脱敏 message = message.replace(/1[3-9]\d{9}/g, function(match) { return match.substring(0,3) + "****" + match.substring(7); }); event.Put("message", message); }

方案四:落盘后处理

如果历史日志已经有敏感信息,需要清洗。

#!/bin/bash# 日志脱敏脚本LOG_DIR="/var/log/app"# 手机号脱敏find$LOG_DIR-name"*.log"-execsed-i -E's/1([3-9])[0-9]{9}/1\1*******/g'{}\;# 身份证脱敏find$LOG_DIR-name"*.log"-execsed-i -E's/[0-9]{6}[0-9]{8}[0-9]{3}[0-9Xx]/******/g'{}\;

最佳实践

分层防护

代码层 → 日志框架层 → 采集层 → 存储层 ↓ ↓ ↓ ↓ 不打印敏感 自动脱敏 二次脱敏 加密存储

建议至少做两层。

敏感数据分类

级别数据类型处理方式
L1绝密密码、密钥禁止打印
L2机密身份证、银行卡强脱敏
L3敏感手机号、邮箱弱脱敏
L4普通姓名、地址可脱敏可不脱敏

禁止打印的内容

// 密码绝对不能打印log.info("用户登录: {}, 密码: {}",username,password);// 错误// Token不能打印log.info("Token: {}",token);// 错误// API Key不能打印log.info("调用第三方API, key={}",apiKey);// 错误

正确做法:

// 只打印是否存在log.info("用户登录: {}, 密码: {}",username,password!=null?"[已设置]":"[未设置]");// Token只打印部分log.info("Token: {}...",token.substring(0,8));

验证脱敏效果

写个测试用例:

@TestpublicvoidtestSensitiveMask(){Useruser=newUser();user.setName("张三");user.setPhone("13812345678");user.setIdCard("320123199001011234");Stringmasked=SensitiveUtil.mask(user);// 验证脱敏后不包含原始数据assertFalse(masked.contains("13812345678"));assertFalse(masked.contains("320123199001011234"));// 验证脱敏格式正确assertTrue(masked.contains("138****5678"));assertTrue(masked.contains("3201**********1234"));}

日志安全审计

除了脱敏,还要控制日志访问权限。

我们有几台日志服务器分布在不同机房,之前权限管理很乱。现在用星空组网把所有节点连起来后,统一通过跳板机访问,权限管控清晰多了。

总结

日志脱敏方案选择:

方案优点缺点推荐场景
代码层最可控需要改代码新项目
日志框架层全局生效性能有损耗老项目改造
采集层不改代码本地日志仍有敏感信息补充方案
落盘后处理处理历史数据不实时应急处理

核心原则:

  1. 能不打印的就不打印
  2. 必须打印的要脱敏
  3. 脱敏要分级
  4. 多层防护

日志安全这块有经验的欢迎交流~

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/5 7:49:39

anything-llm全功能RAG系统助力企业智能化升级

Anything LLM&#xff1a;重塑企业知识智能的RAG实践 在企业数字化转型的深水区&#xff0c;一个看似简单却长期无解的问题反复浮现&#xff1a;如何让员工快速、准确地获取组织内部散落在PDF、手册、邮件和共享盘中的知识&#xff1f;传统搜索工具面对非结构化文档束手无策&am…

作者头像 李华
网站建设 2026/4/3 14:24:25

PE-Labeled CEACAM-5/CD66e FcAvi Tag:上皮癌诊疗的“模块化多功能导航

PE-Labeled CEACAM-5/CD66e Fc&Avi Tag 是一种针对癌胚抗原家族关键成员设计的高级重组蛋白探针。癌胚抗原相关细胞粘附分子5是免疫球蛋白超家族的成员&#xff0c;在正常成人结肠黏膜等上皮组织有痕量表达&#xff0c;但在结直肠癌、非小细胞肺癌、胃癌、乳腺癌及胰腺癌等…

作者头像 李华
网站建设 2026/3/31 5:45:08

Open-AutoGLM如何实现电脑全自动操控?99%的人都不知道的5大核心技术

第一章&#xff1a;Open-AutoGLM如何实现电脑全自动操控&#xff1f;Open-AutoGLM 是一个基于自然语言理解与自动化执行框架的开源项目&#xff0c;旨在通过大语言模型驱动操作系统级任务&#xff0c;实现真正意义上的电脑全自动操控。其核心机制是将用户输入的自然语言指令解析…

作者头像 李华
网站建设 2026/4/8 22:59:52

anything-llm能否用于游戏剧情生成?互动叙事应用测试

Anything-LLM能否用于游戏剧情生成&#xff1f;互动叙事应用测试 在一款开放世界角色扮演游戏中&#xff0c;玩家做出了一个出人意料的选择&#xff1a;他没有拯救被绑架的盟友&#xff0c;反而与敌对势力达成交易。编剧团队原本并未为此设计后续分支——但游戏中的NPC却自然地…

作者头像 李华
网站建设 2026/4/11 8:16:14

LangFlow AppDynamics End User Monitoring

LangFlow 与 AppDynamics&#xff1a;构建可监控的 AI 工作流 在生成式 AI 快速渗透企业应用的今天&#xff0c;一个现实问题日益凸显&#xff1a;如何让复杂的语言模型工作流不仅“跑得起来”&#xff0c;还能“看得清楚”&#xff1f;传统的 LLM 应用开发往往止步于功能实现&…

作者头像 李华
网站建设 2026/4/2 21:14:14

0 基础想转行网安?保姆级攻略:3 个月从小白变 “白帽黑客”!

如何转行黑客/网络安全行业&#xff1f;从0开始保姆级讲解&#xff01; 网络安全技术被广泛应用于各个领域&#xff0c;各大企业都在争抢网络安全人才&#xff0c;这使得网络安全人才的薪资一涨再涨&#xff0c;想转行网络安全开发的人也越来越多。而想要顺利转行网络安全开发&…

作者头像 李华