Log4j和Log4j2 知识

1 什么是log4j

https://www.jianshu.com/p/6d91c352b4e9

Log4j是一个由Java编写可靠、灵活的日志框架,是Apache旗下的一个开源项目;现如今,Log4j已经被移植到了C、C++、Python等语言中,服务更多的Developer;

使用Log4j,我们更加方便的记录了日志信息,它不但能控制日志输出的目的地,也能控制日志输出的内容格式;通过定义不同的日志级别,可以更加精确的控制日志的生成过程,从而达到我们应用的需求;这一切,都得益于一个灵活的配置文件,并不需要我们更改代码。

1.1 log4j和log4j2的区别

  1. 配置文件类型
    • log4j 采用properties的文件作为主配置文件,log4j2采用的是xml, json或者 jsn这种方式来做,可能这也是技术发展的一个必然性
  2. 核心JAR包
    • log4j只需要引入一个jar包即可(log4j 1.2.17),  log4j2则是需要2个核心jar(log4j-core和log4j-api)
  3. 文件名
    • log4j的配置文件名是log4j.xml或者是log4j.properties, log4j2的配置文件名是log4j2.xml
  4. Log调用
  • Log4j调用private final Logger LOGGER = Logger.getLogger(Test.class.getName());
  • Log4j2调用private static Logger logger = LogManager.getLogger(Test.class.getName());

 

2 log4j结构

在Log4j中,主要由三个重要组件构成:

  • Logger:日志对象,负责捕捉日志记录信息;
  • Appender:日志输出目的地,负责把格式好的日志信息输出到指定地方,可以是控制台、磁盘文件等;
  • Layout:日志格式化器,负责发布不同风格的日志信息;

 

3 Log4j 性能优化

  1. 配置滚动日志的时候,若不需要压缩日志,filePattern的文件名不要以gz结尾;
  2. 使用Disruptor异步日志的时候,不要同时使用Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector<asyncRoot>
  3. RollingRandomAccessFile配置immediateFlush="false"属性,这样让I/O线程批量刷盘(这里其实涉及到native方法调用的性能问题);
  4. 可以结合资源情况是否要配置SynchronizeEnqueueWhenQueueFullfalse
  5. 结合实际情况是否要更改I/O线程的WaitStrategy
  6. 若日志可以丢弃,可以配置丢弃策略,配置log4j2.asyncQueueFullPolicy=Discardlog4j2.discardThreshold=INFO「默认」,当队列满时,INFO, DEBUGTRACE级别的日志会被丢弃;

 

4 Log4j 漏洞

https://zhuanlan.zhihu.com/p/444103520

log4j 错误(也称为 log4shell 漏洞,编号为CVE-2021-44228)是一些最广泛使用的 Web 服务器软件 Apache 的弱点。该错误位于开源 log4j 库中,该库是程序员用来加快工作速度并避免重复复杂代码的一组预设命令。

Log4j 缺陷的工作原理

可能有很多服务器都存在这个缺陷,但情况更糟:log4j 错误的工作原理是您可以替换单个文本字符串(一行代码),从而使其从 Internet 上的另一台计算机加载数据。

log4j2的强大之处在于,除了可以输出程序中的变量,它还提供了一个叫Lookup。lookup,顾名思义就是查找、搜索的意思,那在log4j2中,就是允许在输出日志的时候,通过某种方式去查找要输出的内容。

主要看JNDI:JNDI即Java Naming and Directory Interface(JAVA命名和目录接口),它提供一个目录系统,并将服务名称与对象关联起来,从而使得开发人员在开发过程中可以使用名称来访问对象。

 

 

简单粗暴理解:有一个类似于字典的数据源,你可以通过JNDI接口,传一个name进去,就能获取到对象了。

 

 LDAP:LDAP即Lightweight Directory Access Protocol(轻量级目录访问协议),目录是一个为查询、浏览和搜索而优化的专业分布式数据库,它呈树状结构组织数据,就好象Linux/Unix系统中的文件目录一样。目录数据库和关系数据库不同,它有优异的读性能,但写性能差,并且没有事务处理、回滚等复杂功能,不适于存储修改频繁的数据。所以目录天生是用来查询的,就好像它的名字一样。统一身份认证领域。

网络安全中有一个准则:不要信任用户输入的任何信息

假如某一个Java程序中,将浏览器的类型记录到了日志中:

String userAgent = request.getHeader("User-Agent");
logger.info(userAgent);

假如有人发来了一个HTTP请求,他的User-Agent是这样一个字符串:

${jndi:ldap://127.0.0.1/exploit}

log4j2将会对这行要输出的字符串进行解析。首先,它发现了字符串中有 ${},知道这个里面包裹的内容是要单独处理的。发现是JNDI扩展内容。再进一步解析,发现了是LDAP协议,LDAP服务器在127.0.0.1,要查找的key是exploit。最后,调用具体负责LDAP的模块去请求对应的数据。

注意,这里就是核心问题了:JNDI可以远程下载class文件来构建对象!!!

 

 这就是鼎鼎大名的JNDI注入攻击!

 

5 修复

 

 答案是:修复后的log4j2在JNDI lookup中增加了很多的限制:

1.默认不再支持二次跳转(也就是命名引用)的方式获取对象
2.只有在log4j2.allowedLdapClasses列表中指定的class才能获取。
3.只有远程地址是本地地址或者在log4j2.allowedLdapHosts列表中指定的地址才能获取

防护和解决
1、检查代码,及时升级到安全的版本,本次漏洞还涉及众多Apache开源项目,这部分也应该及时更新,采用最新版本2.17.0。
2、恶意流量中可能存在jndi:ladp:// jdni:rmi,IDS和WAF可以编写相应规则从流量中签出攻击流量;
3、添加jvm启动参数-Dlog4j2.formatMsgNoLookups=true
4、修改配置文件log4j2.formatMsgNoLookups=True
5、修改环境变量FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS 设置为true
6、关闭不必要的外网请求;
7、禁用lookup或JNDI服务;
8、jdk升级到最新的版本;

影响 < 2.15.0 的所有 2.x 版本。也就是说,除了最新版本之外的所有版本都受影响。
最直接、有效、稳定的修复方式是:将 log4j-core 升级到 2.15.0 版本
最直接、有效、稳定的修复方式是:将 log4j-core 升级到 2.15.0 版本
最直接、有效、稳定的修复方式是:将 log4j-core 升级到 2.15.0 版本

 

posted @ 2022-11-24 16:46  NingShare  阅读(1414)  评论(0编辑  收藏  举报