首頁 > Java > java教程 > 主體

使用正規表示式在java中使用logstash logback屏蔽日誌

Susan Sarandon
發布: 2024-11-11 18:26:02
原創
252 人瀏覽過

在當今數據驅動的世界中,資料安全最為重要。日誌框架在應用程式監控和偵錯中發揮著至關重要的作用,但它們可能會無意中暴露不應該暴露的敏感資訊。日誌屏蔽是一種有效混淆日誌訊息中敏感資料、保護機密資訊的技術。

了解日誌回溯

Logback 是 Java 應用程式中一個強大且最常用的日誌框架。它提供靈活的配置選項,包括將日誌事件格式化為 JSON 物件的能力。它是 Log4j 框架的繼承者,由於其功能和易用性而迅速流行起來。它由 Logger、Encoders、Layout、Appender、Encoder 組成。

Logger: Logger 是日誌訊息的上下文。應用程式將與此類互動以建立日誌訊息。

編碼器: 編碼器是在 logback 0.9.91 中引入的,負責將事件轉換為位元組數組以及將該位元組數組寫入 OutputStream。作為佈局引入的編碼器只能將事件轉換為字串,這將其範圍限制為非二進位輸出。

佈局: 佈局負責根據使用者的意願格式化日誌請求,而附加程式負責將格式化的輸出傳送到其目的地。

Appenders: 在 logback 中,輸出目標稱為 Appender。這會將日誌訊息放置在其最終目的地。一個 Logger 可以有多個 Appender。目前,控制台、檔案、遠端套接字伺服器、MySQL、PostgreSQL、Oracle 和其他資料庫、JMS 和遠端 UNIX Syslog 守護程式都存在附加程式。

關於 Logstash Logback 編碼器

logstash-logback-encoder 函式庫是增強 Spring Boot 應用程式日誌記錄功能的寶貴工具。它提供了一種以結構化 JSON 格式格式化日誌訊息的便捷方法,使日誌聚合和分析工具(例如 Logstash)可以輕鬆使用它們。 JSON 格式提供了一種結構化且機器可讀的方式來記錄信息,使其成為高級日誌分析和安全措施的理想選擇。 Logstash 的好處

  • JSON 自訂 Logstash 可讓您自訂 JSON 輸出以包含特定欄位和元資料。

  • 動態欄位它還允許根據應用程式上下文動態新增欄位來記錄事件。

  • 提高了可讀性 JSON 格式為日誌事件提供了清晰且易於閱讀的結構。

  • 增強的搜尋和分析日誌聚合工具可以輕鬆解析和查詢 JSON 日誌。

  • 機器解析 JSON 日誌非常適合自動分析和警報系統。

屏蔽日誌資料的解決方案

這裡的主要目標是提供一種解決方案來屏蔽可在運行時自訂和配置的資料。

這是我們的簡單要求

  1. 在日誌中完全封鎖密碼。
  2. 封鎖電話號碼和登入名,日誌中最後 5 位除外。

第 1 步
建立 Spring Boot 應用程式。該解決方案將適用於任何基於 Java 的應用程序,只需很少的自訂。

第 2 步
配置所有正規表示式以屏蔽資料。請記住,正規表示式在資源利用率方面的成本很高。確保您正在調整正規表示式。正規表示式群組將允許我們從字串中選擇所需的子字串。

mask logs with logstash logback in java using regex

第三步
建立一個類別並實作 MessageJsonProvider。該介面來自logstash,允許我們在列印到附加程式之前自訂訊息。每個日誌訊息都會呼叫此介面中的 writeTo 方法。

  • 在start()方法中讀取所有正規表示式並準備包含所有MaskingRule的LogMasker。此方法來自 AbstractJsonProvider,只是將進程啟動標記為 true。

  • MaskingRule 將保存正規表示式模式和一個函數。此函數替換日誌中識別的字串。

@Data
public class MaskingMessagingProvider extends MessageJsonProvider {

    public static final String DEFAULT_RULES_DELIMITER = ",";
    private LogMasker logMasker;
    private String rules;

    public MaskingMessagingProvider() {
        super();
    }

    @Override
    public void start() {
        super.start();
        this.logMasker = LogMasker.create(StringUtils.tokenizeToStringArray(rules, DEFAULT_RULES_DELIMITER));
    }

    @Override
    public void writeTo(JsonGenerator generator, ILoggingEvent event) throws IOException {

        if (isStarted()) {
            JsonWritingUtils.writeStringField(generator, getFieldName(), logMasker.mask(event.getFormattedMessage()));
        }
    }
}

class LogMasker {

    private MaskingRule[] masks;

    public LogMasker(MaskingRule[] masks) {
        super();
        this.masks = masks.clone();
    }

    public static LogMasker create(String[] rules) {

        return new LogMasker(Arrays.stream(rules).map(rule -> MaskingRule.create(rule)).toArray(MaskingRule[]::new));
    }

    public String mask(String input) {
        String transformed = input;
        for (MaskingRule m : masks) {
            transformed = m.mask(transformed);
        }
        return transformed;
    }
}

class MaskingRule {
    public static final int REG_EX_DEFAULT_GROUP_SELECTOR = 2;
    public static final String DEFAULT_REPLACEMENT = "*";

    private Pattern pattern;
    private UnaryOperator<String> replacement;

    public MaskingRule(Pattern maskPattern, UnaryOperator<String> replacement) {
        super();
        this.pattern = maskPattern;
        this.replacement = replacement;
    }

    public static MaskingRule create(String rule) {
        return new MaskingRule(Pattern.compile(rule), (in) -> MaskingRule.maskDataWithReplacement(in, DEFAULT_REPLACEMENT));
    }

    public String mask(String transformed) {
        Matcher matcher = pattern.matcher(transformed);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, replacement.apply(getDataToBeMasked(matcher)));
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    private static String maskDataWithReplacement(String input, String replacement) {
        int repetition = !StringUtils.hasLength(input) ? 0 : input.length();
        return String.join("", Collections.nCopies(repetition, replacement));
    }

    private static String getDataToBeMasked(Matcher matcher) {
        if (matcher.groupCount() > 1) {
            return matcher.group(REG_EX_DEFAULT_GROUP_SELECTOR);
        }
        return matcher.groupCount() > 0 ? matcher.group(1) : "";
    }
}
登入後複製

步驟 4
在 logback-spring.xml 檔案中配置類別。

<configuration>
    <springProperty scope="context" name="rules" source="app.logging.masking.rules"
                    defaultValue=""/>
    <appender name="CONSOLE">



<p><strong>Steps 5</strong><br>
Run the application. For simplicity, i have taken a string which is holding data and printing it at application start up.<br>
</p>

<pre class="brush:php;toolbar:false">@SpringBootApplication
@Slf4j
public class LogDataMaskingApplication {

    public static void main(String[] args) {
        SpringApplication.run(LogDataMaskingApplication.class, args);
        LogDataMaskingApplication.maskingTest();
    }

    public static void maskingTest() {
        String data = "{\"loginName\":\"maskingtest\",\"phoneNumber\":\"9898981212\",\"password\":\"Masking@123\"}";
        log.info(data);
    }

}
登入後複製

mask logs with logstash logback in java using regex

這是非常基本的解決方案,並且根據訊息摘要等要求有很大的增強空間...

您可以在 GitHub 上找到程式碼。

如有任何問題請留言。

以上是使用正規表示式在java中使用logstash logback屏蔽日誌的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板