22

多数のパターンのいずれかのイベントを検索し、パターン内のテキストをマスクされた値に置き換えることができる必要があります。これは、機密情報がログに記録されるのを防ぐためのアプリケーションの機能です。情報は多種多様なソースから得られる可能性があるため、すべての入力にフィルターを適用するのは現実的ではありません。さらに、ロギング以外にも toString() の用途があり、toString() がすべての呼び出し (ロギングのみ) を一様にマスクすることは望ましくありません。

logback.xml で %replace メソッドを使用してみました:

<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %replace(%msg){'f k\="pin">(.*?)&lt;/f','f k\="pin">**********&lt;/f'}%n</pattern>

これは (山括弧を文字エンティティに置き換えた後) 成功しましたが、1 つのパターンしか置き換えることができません。また、同等のことを実行したいと思います

<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %replace(%msg){'pin=(.*?),','pin=**********,'}%n</pattern>

同時に、しかしできません。1 つの %replace で 2 つのパターンをマスクする方法はありません。

interblags で大まかに議論されているもう 1 つの方法は、appender/encoder/layout 階層で何かを拡張することですが、ILoggingEvent をインターセプトしようとするたびに、通常はインスタンス化エラーまたは UnsupportedOperationException によってシステム全体が崩壊します。

たとえば、PatternLayout を拡張してみました。

@Component("maskingPatternLayout")
public class MaskingPatternLayout extends PatternLayout {

    @Autowired
    private Environment env;

    @Override
    public String doLayout(ILoggingEvent event) {
        String message=super.doLayout(event);

        String patternsProperty = env.getProperty("bowdleriser.patterns");

        if( patternsProperty != null ) {
            String[] patterns = patternsProperty.split("|");
            for (int i = 0; i < patterns.length; i++ ) {
                Pattern pattern = Pattern.compile(patterns[i]);
                Matcher matcher = pattern.matcher(event.getMessage());
                matcher.replaceAll("*");
            }
        } else {
            System.out.println("Bowdleriser not cleaning! Naughty strings are getting through!");
        }

        return message;
    }
}

次に、logback.xml を調整します。

<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <layout class="com.touchcorp.touchpoint.utils.MaskingPatternLayout">
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </layout>
    </encoder>
  </appender>

    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <file>logs/touchpoint.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
            <fileNamePattern>logs/touchpoint.%i.log.zip</fileNamePattern>
            <minIndex>1</minIndex>
            <maxIndex>3</maxIndex>
        </rollingPolicy>

        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <maxFileSize>10MB</maxFileSize>
        </triggeringPolicy>
      <encoder>
          <layout class="com.touchcorp.touchpoint.utils.MaskingPatternLayout">
            <pattern>%date{YYYY-MM-dd HH:mm:ss} %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
          </layout>
      </encoder>
    </appender>


  <logger name="com.touchcorp.touchpoint" level="DEBUG" />
  <logger name="org.springframework.web.servlet.mvc" level="TRACE" />

  <root level="INFO">
    <appender-ref ref="FILE" />
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

私は他の多くの挿入を試みたので、誰かが私が試みていることを実際に達成したかどうか、そして彼らが手がかりや解決策を提供できるかどうか疑問に思っていました.

4

5 に答える 5

21

を使用してレイアウトをラップする必要がありますLayoutWrappingEncoder。また、ログバックは春によって管理されていないため、ここでは春を使用できないと思います。

これが更新されたクラスです。

public class MaskingPatternLayout extends PatternLayout {

    private String patternsProperty;

    public String getPatternsProperty() {
        return patternsProperty;
    }

    public void setPatternsProperty(String patternsProperty) {
        this.patternsProperty = patternsProperty;
    }

    @Override
    public String doLayout(ILoggingEvent event) {
        String message = super.doLayout(event);
        
        if (patternsProperty != null) {
            String[] patterns = patternsProperty.split("\\|");
            for (int i = 0; i < patterns.length; i++) {
                Pattern pattern = Pattern.compile(patterns[i]);

                Matcher matcher = pattern.matcher(event.getMessage());
                if (matcher.find()) {
                    message = matcher.replaceAll("*");
                }
            }
        } else {

        }

        return message;
    }

}

およびサンプル logback.xml

<appender name="fileAppender1" class="ch.qos.logback.core.FileAppender">
    <file>c:/logs/kp-ws.log</file>
    <append>true</append>
    <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
        <layout class="com.kp.MaskingPatternLayout">
            <patternsProperty>.*password.*|.*karthik.*</patternsProperty>
            <pattern>%d [%thread] %-5level %logger{35} - %msg%n</pattern>
        </layout>
    </encoder>
</appender>
<root level="DEBUG">
    <appender-ref ref="fileAppender1" />
</root>

アップデート

ここでのより良いアプローチは、初期化中にパターンを設定することです。パターンを何度も再作成することを避けることができ、この実装は現実的なユースケースに近いものです。

public class MaskingPatternLayout extends PatternLayout {

    private String patternsProperty;
    private Optional<Pattern> pattern;

    public String getPatternsProperty() {
        return patternsProperty;
    }

    public void setPatternsProperty(String patternsProperty) {
        this.patternsProperty = patternsProperty;
        if (this.patternsProperty != null) {
            this.pattern = Optional.of(Pattern.compile(patternsProperty, Pattern.MULTILINE));
        } else {
            this.pattern = Optional.empty();
        }
    }

        @Override
        public String doLayout(ILoggingEvent event) {
            final StringBuilder message = new StringBuilder(super.doLayout(event));
    
            if (pattern.isPresent()) {
                Matcher matcher = pattern.get().matcher(message);
                while (matcher.find()) {
    
                    int group = 1;
                    while (group <= matcher.groupCount()) {
                        if (matcher.group(group) != null) {
                            for (int i = matcher.start(group); i < matcher.end(group); i++) {
                                message.setCharAt(i, '*');
                            }
                        }
                        group++;
                    }
                }
            }
            return message.toString();
        }
    
    }

そして、更新された構成ファイル。

<appender name="fileAppender1" class="ch.qos.logback.core.FileAppender">
    <file>c:/logs/kp-ws.log</file>
    <append>true</append>
    <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
        <layout class="com.kp.MaskingPatternLayout">
            <patternsProperty>(password)|(karthik)</patternsProperty>
            <pattern>%d [%thread] %-5level %logger{35} - %msg%n</pattern>
        </layout>
    </encoder>
</appender>
<root level="DEBUG">
    <appender-ref ref="fileAppender1" />
</root>

出力

My username=test and password=*******
于 2014-08-13T07:05:32.143 に答える
4

これが私のアプローチです、多分それは誰かを助けることができます

これを試してみてください。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. 2 番目のステップは、logback.xml に logback 用のアペンダーを作成することです。

    <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("creditCard={} に設定されたカード コンテキスト", creditCard);

  3. その結果、

    ログから 1 行

    creditCard=11111******111 のカード コンテキスト セット

これらのオプションがないと、ログは次の行のようになります

card context set for creditCard=1111111111111
于 2020-04-22T08:49:48.877 に答える