男做直播網(wǎng)站的磁力搜索引擎
背景
日志注入一般指的是惡意用戶輸出換行等內(nèi)容,混淆正常的日志,導(dǎo)致排查問題是無法正確定位問題,因此,我們需要對要打印的日志內(nèi)容進行過濾。
但是,如果是每個接口單獨處理的話,成本較高,因此,我們需要一個統(tǒng)一處理的機制。
當(dāng)然,統(tǒng)一處理可能會誤傷正常的日志,這個需要自己進行斟酌了。我們在絕大情況下不會在打印日志的內(nèi)容中使用換行等特殊字符,所以這樣處理我認為是比較穩(wěn)妥的。
這個處理僅會對用戶輸入的參數(shù)進行處理,不會對堆棧的正常的內(nèi)容處理,所以大部分的日志是可以正常打印出來的。
方案
springboot集成的logback,其配置文件是 org/springframework/boot/logging/logback/base.xml
,其默認參數(shù)配置都在org/springframework/boot/logging/logback/defaults.xml
。我們不打算修改這些配置,而是沿用。
我們對logback進行定制,spring集成的默認log_pattern為:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd'T'HH:mm:ss.SSSXXX}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr(%applicationName[%15.15t]){faint} %clr(${LOG_CORRELATION_PATTERN:-}){faint}%clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}
,中間可以全部不管,輸出的重點就是靠后部分的%m
,這個是一個Converter,對消息進行處理,默認是不進行任何處理,直接輸出原消息,我們對他進行定制。
我們自定義自己的Converter:
import ch.qos.logback.classic.pattern.ClassicConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import org.slf4j.helpers.MessageFormatter;/*** @author */
public class LineSeparatorConverter extends ClassicConverter {@Overridepublic String convert(ILoggingEvent event) {Object[] argumentArray = event.getArgumentArray();// 沒有用戶傳入的參數(shù),直接返回if (argumentArray == null || argumentArray.length == 0) {return event.getFormattedMessage();}Object[] argumentArrayProcessed = new Object[argumentArray.length];for (int i = 0; i < argumentArray.length; i++) {Object o = argumentArray[i];if (o == null || o instanceof Throwable) {argumentArrayProcessed[i] = o;} else {String oString = o.toString();argumentArrayProcessed[i] = cleanLineSeparator(oString);}}return getFormattedMessage(event.getMessage(), argumentArrayProcessed);}public String getFormattedMessage(String message, Object[] argumentArray) {String formattedMessage;if (argumentArray != null) {formattedMessage = MessageFormatter.arrayFormat(message, argumentArray).getMessage();} else {formattedMessage = message;}return formattedMessage;}private String cleanLineSeparator(String line) {if (line == null || line.isEmpty()) {return line;}return line.replace("\n", "\\n").replace("\r", "\\r");}}
然后,聲明logback-spring.xml
,使用spring的默認配置,并且覆蓋%m
的默認Converter,改成我們自己的
<?xml version="1.0" encoding="UTF-8"?><configuration scan="true" scanPeriod="60 seconds" debug="false"><include resource="org/springframework/boot/logging/logback/base.xml"/><!-- 將默認的輸出器改為自定義輸出器,會替換掉換行符,防止日志注入 --><conversionRule conversionWord="m"converterClass="xxx.LineSeparatorConverter"/></configuration>
如果放到了resources目錄下,該文件應(yīng)該可以正常識別到,不需要額外配置。
如果日志處理是一個maven的子模塊,那就手動聲明一下文件位置
logging.config=classpath:logback-spring.xml
,
如果放到其他目錄,寫成:logging.config=file:/xxx/xxx/logback-spring.xml