【问题标题】:How masking of sensitive data is achieved using slf4j framework?使用 slf4j 框架如何实现对敏感数据的屏蔽?
【发布时间】:2013-05-27 14:23:55
【问题描述】:

我想使用 slf4j 框架屏蔽用户名/密码等敏感数据。立即帮助表示赞赏。提前致谢。

【问题讨论】:

    标签: slf4j


    【解决方案1】:

    试试这个。 1.首先,我们应该创建一个类来处理我们的日志(每一行)

    public class PatternMaskingLayout extends PatternLayout {
    
    private Pattern multilinePattern;
    private List<String> maskPatterns = new ArrayList<>();
    
    public void addMaskPattern(String maskPattern) { // invoked for every single entry in the xml
        maskPatterns.add(maskPattern);
        multilinePattern = Pattern.compile(
                String.join("|", maskPatterns), // build pattern using logical OR
                Pattern.MULTILINE
        );
    }
    
    @Override
    public String doLayout(ILoggingEvent event) {
        return maskMessage(super.doLayout(event)); // calling superclass method is required
    }
    
    private String maskMessage(String message) {
        if (multilinePattern == null) {
            return message;
        }
        StringBuilder sb = new StringBuilder(message);
        Matcher matcher = multilinePattern.matcher(sb);
        while (matcher.find()) {
            if (matcher.group().contains("creditCard")) {
                maskCreditCard(sb, matcher);
            } else if (matcher.group().contains("email")) {
                // your logic for this case
            }
        }
        return sb.toString();
    }
    private void maskCreditCard(StringBuilder sb, Matcher matcher) {
        //here is our main logic for masking sensitive data
        String targetExpression = matcher.group();
        String[] split = targetExpression.split("=");
        String pan = split[1];
        String maskedPan = Utils.getMaskedPan(pan);
        int start = matcher.start() + split[0].length() + 1;
        int end = matcher.end();
        sb.replace(start, end, maskedPan);
    }
    

    }

    1. 第二步是我们应该为logback创建appender到logback.xml中

      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
      <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
          <layout class="com.bpcbt.micro.utils.PatternMaskingLayout">
              <maskPattern>creditCard=\d+</maskPattern> <!-- SourcePan pattern -->
              <pattern>%d{dd/MM/yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n%ex</pattern>-->
          </layout>
      </encoder>
      

    2. 现在我们可以在代码中使用记录器

      log.info("card context set for creditCard={}", creditCard);

    3. 结果,我们会看到

      日志中的一行

      为 creditCard=11111******111 设置的卡上下文

    如果没有这些选项,我们的日志会像这一行

    card context set for creditCard=1111111111111
    

    【讨论】:

    • 所以我知道这是一个很老的线程,但有谁知道 Utils.getMaskedPan(pan);来自?为此必须导入什么库?
    • Utils.getMaskedPan(pan) - 这是我自己的方法) 与掩码敏感数据的自定义实现。
    【解决方案2】:

    也许这个库会有所帮助:owasp-security-logging

    OWASP Security Logging Project相关 并提供相关功能:

    LOGGER.info("userid={}", userid);  
    LOGGER.info(SecurityMarkers.CONFIDENTIAL, "password={}", password);
    

    目的是在日志中产生以下输出:

    2014-12-16 13:54:48,860 [main] INFO - userid=joebob
    2014-12-16 13:54:48,860 [main] [CONFIDENTIAL] INFO - password=***********
    

    您可以在Wiki找到更多信息

    【讨论】:

      【解决方案3】:

      假设您使用的是 Java/Groovy。在您的 log4j2.xml 中,添加如下内容:

          <PatternLayout pattern="%mm"/>
      

      然后采用该模式并为其创建转换器:

      @Plugin(name = 'maskLog', category = 'Converter')
      @ConverterKeys(['mm'])
      class MaskLogConverter extends LogEventPatternConverter {
      
          private static final String NAME = 'mm'
      
          private MaskLogConverter(String[] options) {
              super(NAME, NAME)
          }
      
          static LogMaskingConverter newInstance(final String[] options) {
              return new LogMaskingConverter(options)
          }
      
          @Override
          void format(LogEvent event, StringBuilder outputMessage) {
              String message = event.message//.formattedMessage
      
              // Do your masking logic here
      
              outputMessage.append(message)
          }
      }
      

      在该类中,您可以相应地屏蔽、转换、解析等。

      【讨论】:

      • 嗨,我们不能从 application.properties 文件中获取 private static final String NAME = 'mm' 吗?
      【解决方案4】:

      框架本身不会进行屏蔽,您也不应该期望它这样做。将机密信息传递给报告系统是一种非常糟糕的做法。在您的log.info() 呼叫中,确保将密码替换为星号。屏蔽用户名是没有意义的,因为您可能不记录任何内容。

      log.info("Successful login: {0} ********", username);
      

      【讨论】:

      • 您的建议很糟糕,因为手动执行此操作容易出错。最好有一个通用的通用解决方案,以确保没有遗漏任何内容。
      • 根据我的经验,作为审计过程的一部分,您必须手动检查每一次潜在的机密数据泄露。同样,这不是日志框架的责任。
      • 不,log4j 确实支持用星号覆盖密码。
      • 在大型应用程序中检查每个日志调用是否有敏感数据泄漏是不切实际的,而且您永远无法保证人为错误。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-29
      • 2022-12-01
      • 2018-08-15
      • 2015-07-18
      • 2020-05-01
      相关资源
      最近更新 更多