用户输入的参数未做任何验证直接写入日志文件,导致攻击者可以通过特殊字符(\r \n)在日志中注入新的日志条目,破坏系统日志的完整性。例如:test failed to log in. 如果test是可以控制的,就可以通过输入(admin login successfully.\r\n test)将日志修改为:admin login successfully.\r\n Info:test failed to log in. 就注入了一条日志。 一旦 日志的完整性没法保障,那么,会影响它作为证据的有效性。
日志注入的示例代码如下:
- logger.info("Test for Log injection for special char CRLF \r\n End");
- logger.info("Test for Log injection for special char CR \r End");
- logger.info("Test for Log injection for special char LF \n End");
在windows系统下,运行此代码,显示的结果如下:
从显示的结果可以看出,原本是一行日志的,却在日志中显示了两行,也就是注入了一行日志。这里比较奇怪的是,当使用\r时,所有\r之前的日志全部都没有显示。也就是说,攻击者是否可以通过此方法隐藏自己的痕迹???
不同系统的换行符也不一样,所以,也可以根据不同的系统进行针对性的过滤。
操作系统 | 文件换行符 |
Windows | \r\n |
Linux | \n |
Mac | \r\n |
预防的方法之一就是,转义,将\r字符替换为\\r,\n替换为\\n,这一样就可以将\r或者\n处理为不是换行的字符,示例代码如下:
- logger.info("Test for Log injection for special char CRLF \\r\\n End");
- logger.info("Test for Log injection for special char CR \\r End");
- logger.info("Test for Log injection for special char LF \\n End");
显示的结果是:
可以看到这里,将\r和\n作为具体字符打印出来。
预防的方法之二就是利用Log4j的配置自动处理这些导致注入的字符的处理,虽然原理也是将\r替换为\\r,\n替换为\\n,但是,使用起来更简单,具体可以参考: Log4j – Log4j 2 Layouts
可以使用%enc{%m}{CRLF}对换行符进行替换处理。具体配置如下:
- <Appenders>
- <Console name="console" target="SYSTEM_OUT" follow="true">
- <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}][%-5p] [%t] [%c{10}#%M:%L] %enc{%m}{CRLF} %n "/>
- </Console>
- </Appenders>
这样也可以使用log4j框架提供的安全措施实现自动替换。
针对日志注入的另外一种攻击,就是在系统维护人员查看日志时,可能会将日志显示在web页面上,如果日志中含有html标签,可能导致XSS攻击。这一点,在Log4j 2 Layouts中也有描述,可以使用HTML编码来实现,例如:%enc{%m}{HTML}.