背景
日志注入一般指的是恶意用户输出换行等内容,混淆正常的日志,导致排查问题是无法正确定位问题,因此,我们需要对要打印的日志内容进行过滤。
但是,如果是每个接口单独处理的话,成本较高,因此,我们需要一个统一处理的机制。
当然,统一处理可能会误伤正常的日志,这个需要自己进行斟酌了。我们在绝大情况下不会在打印日志的内容中使用换行等特殊字符,所以这样处理我认为是比较稳妥的。
这个处理仅会对用户输入的参数进行处理,不会对堆栈的正常的内容处理,所以大部分的日志是可以正常打印出来的。
方案
springboot集成的logback,其配置文件是 org/springframework/boot/logging/logback/base.xml,其默认参数配置都在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 { @Override public String convert(ILoggingEvent event) { Object[] argumentArray = event.getArgumentArray(); // 没有用户传入的参数,直接返回 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,改成我们自己的
如果放到了resources目录下,该文件应该可以正常识别到,不需要额外配置。
如果日志处理是一个maven的子模块,那就手动声明一下文件位置
logging.config=classpath:logback-spring.xml,
如果放到其他目录,写成:logging.config=file:/xxx/xxx/logback-spring.xml
还没有评论,来说两句吧...