修 log4j 漏洞后感,请大佬解惑

2021-12-11 21:28:34 +08:00
 fighterhit

昨天在修 log4j 漏洞突然有一点疑问,请各位大佬解惑: 首先自己的服务是 maven 和 spring-boot 构建的,昨天先用 mvn dependency:tree -Dincludes=log4j 排查了自己的微服务 A 用的 log4j 2.11 是在第三方包 elasticsearch-6.43 下面,然后根据以往经验,就在自己的 A 服务的 pom.xml 中显示添加 log4j 2.15.0 版本,之前自己服务的 pom 是没有显示声明的,重新打包构建 mvn package。打好包 A.jar 后又将其解压看了下 BOOT-INFO/lib 下面 log4j 相关包都是 2.15.0 了,然后我又解压同目录下的 elasticsearch-6.43.jar 包,下面都是 classes 文件。一开始感觉很理所当然,但突然有几个问题:

  1. 显式的在自己服务的 pom 文件声明使用的依赖包比如 log4j 一定会覆盖下层第三方包依赖的 log4j 吗?这是由 maven 的什么机制决定的?
  2. 虽然自己的 A 服务用 pom 里声明的 log4j 2.15 版本构建出来 jar 包,也就是 classes 文件(我理解为二进制),但它依赖的 elasticsearch-6.43 jar 包 classes 不是已经是根据老版本的 log4j 2.11 构建出来的吗?所以 elasticsearch 这个 jar 包不是还是有问题,还是没有根本解决项目的 log4j 的漏洞问题?难道说 java 的 classes 文件是像动态链接库一样,运行时 elasticsearch-6.43 jar 会调用 2.15 的 log4j jar 包?这是 Java 的什么机制呢?
4810 次点击
所在节点    Java
31 条回复
thevita
2021-12-11 22:55:40 +08:00
by the way, 如果如你所说, 你的 log4j 的依赖引入来自 elasticsearch , 我应该假设你使用的的是 org.elasticsearch:elasticsearch, org.elasticsearch.client:elasticsearch-rest-high-level-client, org.elasticsearch.client:elasticsearch-rest-client 的 api 相关的几个依赖, 这里面依赖的只有 log4j-api, 如果后面的 impl 不是 log4j (对应的 应该是 log4j-core 里面, 这次出漏洞的地方就在这里面)目前看是不受影响的
hand515
2021-12-11 23:34:56 +08:00
@fighterhit 看你这个问题,你对 Java 的理解还不够深入,你以前应该是写 C/C++为主的把?
fighterhit
2021-12-11 23:38:22 +08:00
@hand515 惭愧,写 java 和 go 的 java 现在用得少了,之前看过八股文没用就忘了。
fighterhit
2021-12-11 23:42:05 +08:00
@thevita 的确,一开始看白帽上 https://nosec.org/home/detail/4917.html 说可能都有影响保险起见就全换了
BQsummer
2021-12-11 23:54:49 +08:00
1. maven 指定版本优先,没指定按最短路径优先。
2. 双亲委派原则,不同的类加载器有顺序
LuciusChen
2021-12-12 12:48:15 +08:00
看了评论,学习了
LuciusChen
2021-12-12 12:53:17 +08:00
学习了
SoloCompany
2021-12-12 13:55:18 +08:00
maven 的依赖 resolve 是协作式的, 同一个包 (groupId:artifactId) 只能导入一个版本, 具体 resolve 到的哪一个版本在编译时是确定的, 规则虽然不是特别的复杂, 但也不是一句话能说的清楚, 可以用工具帮助解决冲突

并且实际上, groupId:artifactId 和 package FQN 没有严格对应关系这使得问题会更加复杂一些, 同一个 package 可能会被不同的 artifact 导入了超过了, 那么这时候编译以及运行时使用的是哪一个 jar 就变的不确定了, 这样的情况要尽量避免出现

作为想对面, npm 采取的是完全相反的方式, 就是每个 package 及其依赖都是尽量内蕴的, 两个一级依赖之所以用到了同一个次级依赖, 只不过是因为这个二级依赖的版本号恰巧是相同 (npm 会在条件允许下让它们尽量恰巧相同)

表面看起来 npm 的依赖管理简单易懂, 但实际上却复杂的多的多, 并造成了一大堆遗留到现在都很无语的问题
ezksdo
2021-12-12 14:51:45 +08:00
怎么这么多扯淡的回复,这和 class loader 有个卵关系。java 的 jar 包是没有版本号的 module 也没有,这也是为什么两个不同版本的包会冲突,原因是有相同全限定名的 class (包前缀加类名)。加载时根据 class path 查找对应名字的 class 文件,只要文件结构没改,大体上是兼容的。比如早期的 slf4j 编译需要一个 logger 的实现,slf4j 里有一个空的实现,但是编译完成之后就把它删除了,但你依赖中只要有其他的实现一样可以运行。
fighterhit
2021-12-12 18:13:32 +08:00
@SoloCompany @ezksdo 谢谢大佬们回复,现在已经大致明白了,编译好的 class 文件只是有对依赖的类的引用(类似只保留了依赖的类名、函数名而已,感觉理解成动态链接库也差不多?),没有具体的版本号。由于此前已经在 pom 指定了 2.15 版本的 log4j ,也就是解压后 BOOT-INFO 下唯一存在的 log4j 2.15 jar 包,因此在程序启动时会进行类加载,会根据程序中引用了哪些类,根据其完整的类名去查找、加载依赖的类 log4j ,这时候加载的实际就是 BOOT-INFO 下的 log4j 2.15 jar 包,这时候不管是自己的程序还是依赖的其它第三方包比如 elasticseach 等都会使用加载的 2.15 log4j 。
qiany
2021-12-13 09:53:23 +08:00
@fighterhit elasticsearch 调用的只是接口吧 用的是新的实现...我猜的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/821572

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX