德国网站后缀,鞍山网站建设营销,国外比较好的资源网站,企业网站用个人备案被安全部门约谈了一次。
原因是日志里明文打印了用户手机号、身份证号#xff0c;还被导出到了测试环境。这要是出了事#xff0c;GDPR罚款能让公司破产。
花了两周时间做日志脱敏#xff0c;整理一下方案。
为什么要日志脱敏
日志里经常会有#xff1a;
手机号、身份…被安全部门约谈了一次。原因是日志里明文打印了用户手机号、身份证号还被导出到了测试环境。这要是出了事GDPR罚款能让公司破产。花了两周时间做日志脱敏整理一下方案。为什么要日志脱敏日志里经常会有手机号、身份证号银行卡号、密码别笑真有人打印地址、邮箱Token、API Key这些数据如果被运维人员看到 → 内部泄露风险日志被导出 → 外部泄露风险日志被攻击者获取 → 直接完蛋方案一代码层脱敏最可控的方式在打日志的地方处理。1.1 自定义toStringpublicclassUser{privateStringname;privateStringphone;privateStringidCard;OverridepublicStringtoString(){returnUser{namemaskName(name)\, phonemaskPhone(phone)\, idCardmaskIdCard(idCard)\};}privateStringmaskPhone(Stringphone){if(phonenull||phone.length()!11)returnphone;returnphone.substring(0,3)****phone.substring(7);}privateStringmaskIdCard(StringidCard){if(idCardnull||idCard.length()10)returnidCard;returnidCard.substring(0,4)**********idCard.substring(idCard.length()-4);}privateStringmaskName(Stringname){if(namenull||name.length()2)returnname;returnname.charAt(0)*.repeat(name.length()-1);}}打印出来User{name张*, phone138****5678, idCard3201**********1234}1.2 注解方式更优雅一点用注解标记敏感字段// 自定义注解Target(ElementType.FIELD)Retention(RetentionPolicy.RUNTIME)publicinterfaceSensitive{SensitiveTypetype();}publicenumSensitiveType{PHONE,ID_CARD,NAME,BANK_CARD,EMAIL}// 使用注解publicclassUser{Sensitive(typeSensitiveType.NAME)privateStringname;Sensitive(typeSensitiveType.PHONE)privateStringphone;Sensitive(typeSensitiveType.ID_CARD)privateStringidCard;}// 脱敏工具类publicclassSensitiveUtil{publicstaticStringmask(Objectobj){if(objnull)returnnull;Class?clazzobj.getClass();StringBuildersbnewStringBuilder(clazz.getSimpleName(){);Field[]fieldsclazz.getDeclaredFields();for(inti0;ifields.length;i){Fieldfieldfields[i];field.setAccessible(true);Stringvalue;try{ObjectfieldValuefield.get(obj);if(field.isAnnotationPresent(Sensitive.class)){Sensitiveannotationfield.getAnnotation(Sensitive.class);valuedoMask(String.valueOf(fieldValue),annotation.type());}else{valueString.valueOf(fieldValue);}}catch(IllegalAccessExceptione){valueN/A;}sb.append(field.getName()).append().append(value).append();if(ifields.length-1)sb.append(, );}returnsb.append(}).toString();}privatestaticStringdoMask(Stringvalue,SensitiveTypetype){if(valuenull||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:intatIndexvalue.indexOf();returnatIndex2?value.substring(0,2)***value.substring(atIndex):value;default:returnvalue;}}}使用log.info(用户信息: {},SensitiveUtil.mask(user));// 输出用户信息: User{name张*, phone138****5678, idCard3201**********1234}方案二日志框架层脱敏在Logback/Log4j2层面统一处理。2.1 Logback自定义ConverterpublicclassSensitivePatternConverterextendsClassicConverter{privatestaticfinalPatternPHONE_PATTERNPattern.compile(1[3-9]\\d{9});privatestaticfinalPatternIDCARD_PATTERNPattern.compile(\\d{17}[\\dXx]);privatestaticfinalPatternEMAIL_PATTERNPattern.compile([\\w.][\\w.]);OverridepublicStringconvert(ILoggingEventevent){Stringmessageevent.getFormattedMessage();// 手机号脱敏messagePHONE_PATTERN.matcher(message).replaceAll(m-m.group().substring(0,3)****m.group().substring(7));// 身份证脱敏messageIDCARD_PATTERN.matcher(message).replaceAll(m-m.group().substring(0,4)**********m.group().substring(14));// 邮箱脱敏messageEMAIL_PATTERN.matcher(message).replaceAll(m-{Stringemailm.group();intatIndexemail.indexOf();returnatIndex2?email.substring(0,2)***email.substring(atIndex):email;});returnmessage;}}!-- logback.xml --configurationconversionRuleconversionWordsensMsgconverterClasscom.example.SensitivePatternConverter/appendernameCONSOLEclassch.qos.logback.core.ConsoleAppenderencoderpattern%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger - %sensMsg%n/pattern/encoder/appender/configuration这样所有日志自动脱敏无需改业务代码。2.2 Log4j2 RewritePolicyPlugin(nameSensitiveRewritePolicy,categoryCore,elementTyperewritePolicy)publicclassSensitiveRewritePolicyimplementsRewritePolicy{OverridepublicLogEventrewrite(LogEventevent){Messagemessageevent.getMessage();StringformattedMessagemessage.getFormattedMessage();// 脱敏处理StringmaskedMessagemaskSensitiveData(formattedMessage);returnnewLog4jLogEvent.Builder(event).setMessage(newSimpleMessage(maskedMessage)).build();}privateStringmaskSensitiveData(Stringmessage){// 同上正则替换returnmessage;}}方案三日志采集层脱敏在Logstash/Filebeat采集时处理。3.1 Logstash Filterfilter{# 手机号脱敏mutate{gsub[message,1[3-9]\d{9},1**********]}# 身份证脱敏mutate{gsub[message,\d{17}[\dXx],****]}# 银行卡脱敏mutate{gsub[message,\d{16,19},****]}}3.2 Filebeat Processorprocessors:-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 -Es/1([3-9])[0-9]{9}/1\1*******/g{}\;# 身份证脱敏find$LOG_DIR-name*.log-execsed-i -Es/[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(){UserusernewUser();user.setName(张三);user.setPhone(13812345678);user.setIdCard(320123199001011234);StringmaskedSensitiveUtil.mask(user);// 验证脱敏后不包含原始数据assertFalse(masked.contains(13812345678));assertFalse(masked.contains(320123199001011234));// 验证脱敏格式正确assertTrue(masked.contains(138****5678));assertTrue(masked.contains(3201**********1234));}日志安全审计除了脱敏还要控制日志访问权限。我们有几台日志服务器分布在不同机房之前权限管理很乱。现在用星空组网把所有节点连起来后统一通过跳板机访问权限管控清晰多了。总结日志脱敏方案选择方案优点缺点推荐场景代码层最可控需要改代码新项目日志框架层全局生效性能有损耗老项目改造采集层不改代码本地日志仍有敏感信息补充方案落盘后处理处理历史数据不实时应急处理核心原则能不打印的就不打印必须打印的要脱敏脱敏要分级多层防护日志安全这块有经验的欢迎交流~