ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

log4j 升到 2.25.4 就安全了吗?这批 7 条公告里有 1 条 Dependabot 根本报不出来

log4j 升到 2.25.4 就安全了吗?这批 7 条公告里有 1 条 Dependabot 根本报不出来 先说清楚:这批不是 Log4Shell,全是 medium如果你是搜「log4j 漏洞」进来的,大概率想找的是CVE-2021-44228。这篇不是讲那个的。Apache Log4j 在 2025/2026 年发了一批新的公告,7 条,全部 medium,最高 CVSS v4 只有 6.9,一条 RCE 都没有。它们有个统一的机理,而这个机理恰好是自动化工具最不擅长的那种:你的配置在没有任何报错的情况下失效了,而你以为它还在保护你。属性被静默忽略:verifyHostName配了等于没配;属性被静默改名:换行转义悄悄停止工作,TLS framing 悄悄降级成明文 TCP;日志被静默丢掉:某些字符让整条日志事件消失,只进内部 status logger。所以光看版本号看不出你到底中没中 ——要读配置。这也是我写那个工具的原因。一、这批里最容易踩的一脚:升到 2.25.4 的人没升到位7 条里6 条的修复版都 ≤2.25.4:CVE模块修复版CVE-2026-34477log4j-core2.25.4CVE-2026-34478log4j-core2.25.4CVE-2026-34480log4j-core2.25.4CVE-2026-34479log4j-1.2-api2.25.4CVE-2026-34481log4j-layout-template-json2.25.4CVE-2025-68161log4j-core2.25.3看完这张表,几乎所有人都会得出同一个答案:升到 2.25.4。但还有第 7 条:CVE模块修复版CVE-2026-49844log4j-api2.25.5(2.26 线要 2.26.1)它的 advisory 原文写着自己是CVE-2026-34481的不完整修复:The fix released in version2.25.4did not cover all affected code paths.CVE-2026-49844 was assigned to the remaining issue, which concerns theMapMessage.asJson()serialization in Apache Log4j API and is fixed in versions2.25.5and2.26.1.而这一条,机器读不到。二、为什么说「机器读不到」我按坐标反查了 GitHub 的 advisory 数据库(Dependabot 用的就是这份索引):# 注意:git bash 下 gh api 的路径不要加前导斜杠gh api-XGET advisories-fcve_idCVE-2026-49844\--jq.[] | {ghsa: .ghsa_id, type: .type, vulns: (.vulnerabilities | length)}结果:{ghsa:GHSA-qv9r-c865-cp47,type:unreviewed,vulns:0}type是unreviewed,而且vulnerabilities数组是空的——没有包名、没有版本区间、没有修复版。也就是说,不存在任何可以和你的依赖树比对的数据。对比一下同批的另一条:gh api-XGET advisories-fcve_idCVE-2026-34480\--jq.[] | {ghsa: .ghsa_id, type: .type, vulns: (.vulnerabilities | length)}# {ghsa: GHSA-3pxv-7cmr-fjr4, type: reviewed, vulns: 2}换个源(OSV.dev)结论一样,而且更干净 —— 另外 6 条都能通过 GHSA alias 拿到 Maven 坐标,只有它连 alias 都没有:curl-shttps://api.osv.dev/v1/vulns/CVE-2026-49844|python-c import json,sys; djson.load(sys.stdin); print(aliases , d.get(aliases))# aliases Nonecurl-shttps://api.osv.dev/v1/vulns/CVE-2026-34480|python-c import json,sys; djson.load(sys.stdin); print(aliases , d.get(aliases))# aliases [GHSA-3pxv-7cmr-fjr4]这里必须说句公道话,免得被读成别的意思。unreviewed是 GitHub 的正常流程状态(NVD 自动导入、还没人工标注受影响包),不是失职,也不是 Dependabot 有 bug。它就是这条数据现在还不存在。而这批公告最讽刺的地方在于:唯一把正确答案从 2.25.4 顶到 2.25.5 的那一条,恰好是它。三、顺带说一个更普遍、但不是工具的错的问题我最初以为这批 7 条全在log4j-core上。错了,它们散在 4 个模块上:模块命中条目该升到log4j-core34477 / 34478 / 34480 / 681612.25.4log4j-api498442.25.5(2.26 线:2.26.1)log4j-1.2-api344792.25.4log4j-layout-template-json344812.25.4目标版本不是同一个数字。而绝大多数项目的 pom 里只写log4j-core(log4j-api靠它传递进来,另两个按需引入),按那一个坐标反查只看得到4 条。但这一条不是 Dependabot 的错,别混着写。它按你真实的依赖树逐模块告警,那 3 条它报得出来。会漏的是「我只关心 log4j-core 的版本号」这个人为习惯 ——尤其当你在dependencyManagement里单独钉过log4j-api、或某个第三方 BOM 覆盖了它,四个模块的版本就会错开,而「我把 log4j 升到 2.25.4 了」这句话此时只对了一部分。所以两个数字要分开记:按单坐标看少 3 条(习惯问题)vs真正报不出来的 1 条(数据问题)。四、另一条补丁缺口链:verifyHostName配了六年等于没配第二条链更早,而且更容易让人误以为自己安全:CVE-2025-68161:SocketAppender 不做 TLS 主机名校验。官方说升2.25.3。CVE-2026-34477:上面那个修复不完整—— 它只处理了log4j2.sslVerifyHostNamesystem property那条路,没处理Ssl verifyHostNametrue配置属性那条路。要2.25.4。原文:The fix for CVE-2025-68161 wasincomplete: it addressed hostname verification onlywhen enabled via thelog4j2.sslVerifyHostNamesystem property, but not when configuredthrough theverifyHostNameattribute of theSslelement.Although theverifyHostNameconfiguration attribute was introduced in Log4j Core2.12.0,it wassilently ignored in all versions through 2.25.3.2.12.0是 2019 年。也就是说,如果你是在log4j2.xml里用属性配主机名校验的,那它从引入那天起一直没生效,而配置文件看起来完全正常。而这条链最坑的地方是:照 68161 升到 2.25.3 的人,主观上已经修完了——他是最不会再回头查的那批人。五、光报版本不够,得回答「这 7 条里我真中几条」这批每一条都要求你用了某个特定的 layout 或 appender:CVE触发条件(取自官方原文)CVE-2026-34477Ssl的verifyHostName属性 Socket / Syslog / SMTP appenderCVE-2025-68161SocketAppender TLSCVE-2026-34478直接配Rfc5424Layout(用SyslogAppender的不受影响)CVE-2026-34480log4j-core 的XmlLayoutCVE-2026-34479桥的Log4j1XmlLayout,或 log4j 1 兼容层 org.apache.log4j.xml.XMLLayoutCVE-2026-34481JsonTemplateLayoutMapMessage/ObjectMessage里的浮点值CVE-2026-49844JsonTemplateLayout的 message resolver,或MapMessage.asJson()而这些东西全都写在log4j2.xml里,能读。实测同一套装了受影响版本的四个模块:配置是最常见的那种(ConsoleRollingFilePatternLayout)→ 版本层报7 条,真中 0 条配置里有SocketSsl verifyHostNameRfc5424LayoutXmlLayout→ 报 7 条,真中 4 条两个负判据是官方原文明说的,工具单独成一档:用SyslogAppender的不中 34478(原文:Users of theSyslogAppenderare not affected);只用 HTTP appender 的不中 34477(原文:This issue does not affect users of the HTTP appender)。这一档和「我没找到」的可靠程度完全不同 —— 前者有原文背书,后者只是我没看见。 这里有两个坑,只 grep 名字必踩一组另一组差别verifyHostName(大写 N,Ssl)→中 34477verifyHostname(小写 n,HTTP appender)→ 官方写明不受影响一个字母的大小写XmlLayout(34480,log4j-core)Log4j1XmlLayout(34479,1.2-api 桥)前者是后者的子串两组的结论都是相反的。所以工具在配置层做结构化解析(XML 走 JDK 的 DOM 且关掉外部实体,properties 按xxx.type Foo建「前缀→插件」映射)而不是文本匹配 ——只有读出「这个属性挂在哪个元素上」,才能区分上面那两组。YAML / JSON 没有 JDK 内置解析器(而我坚持这工具零运行时依赖),只能文本匹配。报告会把那几条标成「文本依据」并说明弱在哪,不会冒充成结构化结论。六、工具# Release 里直接下 jar,零依赖,不联网java-jarlog4j-check.jar app.jar# fat jar 里就带着 log4j2.xml,一步到位java-jarlog4j-check.jar ./target ./srcjava-jarlog4j-check.jar ~/.m2/repository --no-confighttps://github.com/xiaoqiMikko/log4j-check它输出三段:①四个模块各自扫到的版本;②配置里找到的触发条件(带文件与行号证据);③逐条求交集后你该升到哪个版本,以及你是不是正处在「已经升过级、以为修完了」的窗口里。配置在归档内部也扫(BOOT-INF/classes/、WEB-INF/classes/),所以只丢一个 Spring Boot fat jar 给它就够 ——不需要源码树。log4j2-spring.xml/log4j2-test.xml/log4j.xml(1 兼容层)都认。判定表不是手抄的,由脚本从两个一手源生成(Apache 官方 CycloneDX VDRGitHub advisory 按坐标反查),17 条断言任一不满足就中止不写文件。 顺便留个对别人也有用的发现:/repos/apache/logging-log4j2/security-advisories实测返回 0 条—— Apache 不走 GitHub Security Advisories 那套流程。如果你写脚本盯 Apache 系组件的安全公告,只查那个端点会得到「一切太平」,而且不报错。真正机器可读的一手源是https://logging.apache.org/cyclonedx/vdr.xml(CycloneDX VDR),逐模块给精确版本区间、带描述与修复建议原文,比爬 HTML 好得多。 这个工具不能证明什么(两个方向都得说)「没找到触发条件」不等于安全,至少四种情况会让它变成假的安心:配置是代码里构建的(ConfigurationBuilder/Configurator.initialize),配置文件里没有那个元素;配置运行时才注入(log4j2.configurationFile指向别处、容器里挂进来);你依赖的第三方库自带一份 log4j2 配置而没被扫到;你压根没把配置传进来 —— 这种情况报告会单独标成「本次没看到配置」,而不是「不适用」。这两句话该导致完全不同的动作,所以我让它们在报告里长得不一样。「触发条件全部成立」也不等于确认中招:多数条目还要求「攻击者能控制那个被记进日志的值」,这一点工具判不了。所以它的结论只够用来排优先级,不够用来宣布事故。不覆盖 log4j 1.x(log4j:log4j)—— 扫到会告警但不判定,它是另一套代码。最后这批公告值得花二十分钟的理由,不是它有多危险(它不危险,全是 medium),而是它属于版本号看不出来的那一类:你的配置写得好好的,升级也照着 advisory 做了,而某个安全设置已经悄悄失效了很久。顺手留个我自己的教训:我一开始只查了log4j-core一个坐标,得出「4 条、修复版统一 2.25.4」。这三个数字后来全错了。把两个源摆在一起比一遍,才是 7 条、4 个模块、2.25.5。「我以为只有一个源」这件事本身,就得用第二个源去查。
返回列表