Java日志体系

前段时间Logj42 漏洞闹得沸沸扬扬,公司内部MSF框架及各应用也都在排查是否存在漏洞,并经过多个版本升级,趁这个机会深入了解下JAVA日志生态体系。

log4j2漏洞

远程代码执行漏洞 CVE-2021-44228

存在JNDI注入漏洞,当用户输入数据进行日志记录是,即可触发此漏洞,在启用消息查找替换时执行从LDAP服务器加载的任意代码。

影响版本:2.0 - 2.15.0-rc1

修复版本:2.15.0 (Java 8)

远程代码执行漏洞 CVE-2021-45046

该漏洞为 CVE-2021-44228 修复的绕过,在某些特殊配置的情况下可能造成远程代码执行。当Pattern Layouts配置带有Context Lookup时(例如:$${ctx:loginId})容易受到这种情况的影响,成功利用该漏洞的攻击者能够造成远程代码执行

影响版本:2.0 - 2.15.0

修复版本:2.16.0 (Java 8 2.12.2 (Java 7)

拒绝服务攻击漏洞 CVE-2021-45105

当日志配置使用带有Context Lookups的非默认 Pattern Layout(例如**$${ctx:loginId**})时,攻击者可以通过构造包含递归查找的恶意输入数据,触发无限循环,导致 StackOverflowError,最终进程崩溃。

影响版本:2.0 <= 2.16.0

修复版本:2.17.0 (Java 8) 2.12.3 (Java 7) 2.3.1 (Java 6)

远程代码执行漏洞 CVE-2021-44832

L攻击者通过将恶意的JNDI URI数据源写入JDBC Appender中,通过该JNDI URI可以远程加载代码并执行。在攻击者拥有修改配置文件权限时才可远程执行任意代码,利用难度较大。

影响版本:2.0 - 2.17.0

修复版本:2.17.1 (Java 8) 2.12.4 (Java 7) 2.3.2 (Java 6)

日志体系

今天索性就彻底了解下JAVA的日志发展体系

System.out和System.err

最早的日志记录方式,不灵活也不可配置,要么就是全部打印,要么就是全部不打印,没有日志级别,没有format,啥都没。

Log4j

1996年E.U.SEMPER(欧洲安全电子市场)决定编写自己的日志api,后来演变为log4j(作者 Ceki Gülcü)一经推出就得到了广泛应用,成为Java日志的标准,并成为了Apache的项目,2015年停止维护。

JUL(Java Util Logging)

Apache要求把log4j并入到JDK,遭到SUN公司拒绝,并在JDK1.4版本后,2002年2月推出了自己的日志库Java Util Logging。很多地方但显然比不过已经发布很多年的log4j。

JCL(Jakarta Commons Logging)

2002年8月Apache又推出了日志接口Jakarta Commons Logging,也就是日志抽象层,提供了一个默认实现Simple Log

只要依赖了JCL接口,就可以很方便的在Log4jJUL以及Simple Log之间做切换。

log4j2漏洞

远程代码执行漏洞 CVE-2021-44228

存在JNDI注入漏洞,当用户输入数据进行日志记录是,即可触发此漏洞,在启用消息查找替换时执行从LDAP服务器加载的任意代码。

影响版本:2.0 - 2.15.0-rc1

修复版本:2.15.0 (Java 8)

远程代码执行漏洞 CVE-2021-45046

该漏洞为 CVE-2021-44228 修复的绕过,在某些特殊配置的情况下可能造成远程代码执行。当Pattern Layouts配置带有Context Lookup时(例如:$${ctx:loginId})容易受到这种情况的影响,成功利用该漏洞的攻击者能够造成远程代码执行

影响版本:2.0 - 2.15.0

修复版本:2.16.0 (Java 8 2.12.2 (Java 7)

拒绝服务攻击漏洞 CVE-2021-45105

当日志配置使用带有Context Lookups的非默认 Pattern Layout(例如**$${ctx:loginId**})时,攻击者可以通过构造包含递归查找的恶意输入数据,触发无限循环,导致 StackOverflowError,最终进程崩溃。

影响版本:2.0 <= 2.16.0

修复版本:2.17.0 (Java 8) 2.12.3 (Java 7) 2.3.1 (Java 6)

远程代码执行漏洞 CVE-2021-44832

L攻击者通过将恶意的JNDI URI数据源写入JDBC Appender中,通过该JNDI URI可以远程加载代码并执行。在攻击者拥有修改配置文件权限时才可远程执行任意代码,利用难度较大。

影响版本:2.0 - 2.17.0

修复版本:2.17.1 (Java 8) 2.12.4 (Java 7) 2.3.2 (Java 6)

日志体系

今天索性就彻底了解下JAVA的日志发展体系

System.out和System.err

最早的日志记录方式,不灵活也不可配置,要么就是全部打印,要么就是全部不打印,没有日志级别,没有format,啥都没。

Log4j

1996年E.U.SEMPER(欧洲安全电子市场)决定编写自己的日志api,后来演变为log4j(作者 Ceki Gülcü)一经推出就得到了广泛应用,成为Java日志的标准,并成为了Apache的项目,2015年停止维护。

JUL(Java Util Logging)

Apache要求把log4j并入到JDK,遭到SUN公司拒绝,并在JDK1.4版本后,2002年2月推出了自己的日志库Java Util Logging。很多地方但显然比不过已经发布很多年的log4j。

JCL(Jakarta Commons Logging)

2002年8月Apache又推出了日志接口Jakarta Commons Logging,也就是日志抽象层,提供了一个默认实现Simple Log

只要依赖了JCL接口,就可以很方便的在Log4jJUL以及Simple Log之间做切换。

Slf4j(Simple Logging Facade for Java)

The Simple Logging Facade for Java (SLF4J) serves as a simple facade or abstraction for various logging frameworks (e.g. java.util.logging, logback, log4j) allowing the end user to plug in the desired logging framework at deployment time.

Java的简单日志记录外观 (SLF4J) 用作各种日志记录框架 (例如java.util.Logging,logback,log4j) 的简单外观或抽象,允许最终用户在部署时插入所需的日志记录框架

Ceki Gülcü 离开Apache后,于是于2005年推出了一套新日志接口:Slf4j(Simple Logging Facade for Java),后面也确实证明了Slf4j是要比JCL在很多地方更优秀。

但是由于Slf4j出来的较晚,而且还只是一个日志接口,之前已经出现的日志产品,如JULLog4j都是没有实现这个接口的,所以大佬自己撸了一套适配的桥接包,实现了java日志界的大一统。

简单来说

Logback

由于其他日志框架使用Slf4j,需要使用适配桥接包,也就是之前的日志产品都不是正统的Slf4j的实现,2006年,Ceki Gülcü又撸了一套原生实现Slf4j接口的Logback应运而生,

https://logback.qos.ch/reasonsToSwitch.html

Logback brings a large number of improvements over log4j 1.x, big and small. They are too many to enumerate exhaustively. Nevertheless, here is a non-exhaustive list of reasons for switching to logback from log4j 1.x. Keep in mind that logback is conceptually very similar to log4j 1.x as both projects were founded by the same developer. If you are already familiar with log4j 1.x, you will quickly feel at home using logback.

大概意思就是比log4j1.x有很多改进,可以很方便从log4j1.x切换到logback

Log4j2

在2012年,Apache直接推出了新项目Log4j2,不是Log4j1.x升级,因为Log4j2完全不兼容Log4j1.x

并且Log4j2几乎涵盖Logback所有的特性,并且相比Logback拥有:

  • 更简化的配置
  • 更强大的参数格式化
  • 最夸张的异步性能

并且很微妙的,Log4j2几乎涵盖Logback所有的特性(这不是对着干是啥~而且还有抄袭的嫌疑。。。哈哈哈),更甚者的Log4j2也搞了分离的设计,分化成log4j-apilog4j-core,这个log4j-api也是日志接口,log4j-core才是日志产品。。。

Log4j 2 contains next-generation Asynchronous Loggers based on the LMAX Disruptor library. In multi-threaded scenarios Asynchronous Loggers have 18 times higher throughput and orders of magnitude lower latency than Log4j 1.x and Logback.

log4j2异步日志使用了LMAX Disruptor , 一个无锁的线程间通信框架, 并发性能大大提升。

从图上可以看出,log4j2的异步(全异步,非混合模式)下的性能,远超log4j1和logback。压力越大的情况下,吞吐上的差距就越大。在64线程测试下,log4j2的吞吐达到了180w+/s,而logback/log4j1只有不到20w,相差近十倍

最佳实践

  1. 不要使用root权限去启动进程,漏洞攻击者可以使用root权限做太多事情。
  2. 我们应该依赖日志的抽象,而不是日志的实现,使用日志接口的API而不是直接使用日志实现的API
  3. 日志实现的依赖只添加一个,依赖多个日志产品,会让应用处理日志显得更复杂,无法统一控制。
  4. 日志的scope 设置为runtime ,保证日志的产品的依赖只有在运行时需要,编译时不需要,开发就不会使用到日志实现的API了。
  5. Log4j2仍是然是目前性能最好的日志框架。

参考文献

  1. https://logging.apache.org/log4j/2.x/manual/async.html#Performance
  2. https://logging.apache.org/log4j/2.x/security.html
  3. https://logback.qos.ch/index.html
  4. https://www.slf4j.org/
  5. https://lmax-exchange.github.io/disruptor/disruptor.html
  6. https://new.qq.com/omn/20211228/20211228A0559300.html
  7. https://tech.meituan.com/2016/11/18/disruptor.html

Java日志体系
https://zhengshuoo.github.io/posts/010-log-system
作者
zhengshuo
发布于
2022年1月27日
许可协议