CVE-2026-54665:ApacheNiFi中的预认证主机头注入漏洞"

admin 2026-10-20 16:53:24 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

cover_image

CVE-2026-54665:Apache NiFi 中的预认证主机头注入漏洞

Ots安全

2026年6月21日 11:55
广东

在小说阅读器读本章

去阅读

威胁简报

恶意软件

漏洞攻击

CVE-2026-54665:Apache NiFi 中的预认证主机头注入漏洞

发布日期:2026-06-20报告日期:2026-05-15严重性:5.4 中等(基线)/ 8.1 高(使用 OIDC)状态:已在 NiFi 2.10.0 中修复CWE:CWE-444(HTTP 请求解析不一致)+ CWE-601(开放重定向)

Apache NiFi 中存在预认证主机头注入漏洞。任何未经认证的客户端都可以发送 <host>X-Forwarded-Host或 X-ProxyHost<host> 值,并且该值会被 NiFi 为 OAuth2 重定向、SAML SP 实体、CSRF cookie 域和公共端点构建的 URI 所反映出来/nifi-api/authentication/configuration。受影响版本:0.0.1 至 2.9.0。已在 2.10.0 中修复。

有趣的地方不在于这个 bug 本身,而在于它是如何产生的。2025 年的一次重构(NIFI-14209)删除了HostHeaderHandler之前强制执行已记录nifi.web.proxy.host十年的允许列表的组件,并用一个仅验证端口的自定义程序取而代之。重构后,允许列表仍然出现在文档和配置中,但在运行时,没有任何程序会读取主机部分。

漏洞

nifi-commons/nifi-web-servlet-shared/src/main/java/org/apache/nifi/web/servlet/shared/StandardRequestUriProvider.java:97-115:

private String getHost(final HttpServletRequest request) {    final String host;    final String serverName = request.getServerName();    final String headerHost = getFirstHeader(request,        ProxyHeader.PROXY_HOST,        // X-ProxyHost        ProxyHeader.FORWARDED_HOST,    // X-Forwarded-Host        ProxyHeader.HOST               // Host    );    if (headerHost == null) {        host = serverName;    } else {        final Matcher matcher = HOST_PATTERN.matcher(headerHost);        if (matcher.matches()) {            host = matcher.group(FIRST_GROUP);        } else {            host = serverName;        }    }    return host;}

匹配模式为^([^:]+):?([1-9][0-9]{2,4})?$:。它接受主机部分不包含冒号的任何字符串。例如attacker.example.com:,,nifi-prod.example.com.evil-attacker.net。127.0.0.1全部匹配。没有允许列表检查。

对比一下同一文件getPath()往下几行的内容:它会对 <value> X-ProxyContextPath、 <value> X-Forwarded-Context 和 <value> 进行验证,并在值不在允许列表中时抛出异常。主机检查只是忘记执行同样的操作了。X-Forwarded-Prefixnifi.web.proxy.context.pathIllegalArgumentException

不验证主机的允许列表

NiFiProperties.java:1603-1614将属性解析nifi.web.proxy.host成列表:

public List<String> getAllowedHostsAsList() {    String rawProperty = getProperty(WEB_PROXY_HOST, \"\");    List<String> hosts = Arrays.asList(rawProperty.split(\",\"));    return hosts.stream()            .map(this::normalizeHost)            .filter(host -> !StringUtils.isBlank(host))            .collect(Collectors.toList());}

唯一的调用者是FrameworkServerConnectorFactory.getValidPorts(),它仅从每个条目中提取端口,以构建 Jetty 监听器接受的端口集:

private static Set<Integer> getValidPorts(final NiFiProperties properties) {    final Set<Integer> validPorts = new HashSet<>();    final int serverPort = getPort(properties);    validPorts.add(serverPort);    final List<String> allowedHosts = properties.getAllowedHostsAsList();    for (final String allowedHost : allowedHosts) {        final Matcher portMatcher = HOST_PORT_PATTERN.matcher(allowedHost);        if (portMatcher.matches()) {            final String portGroup = portMatcher.group(PORT_GROUP);            final int allowedPort = Integer.parseInt(portGroup);            validPorts.add(allowedPort);        }    }    return validPorts;}

因此,如果操作员阅读了管理指南中关于主机配置的部分nifi.web.proxy.host,将其设置为某个值nifi.example.com,nifi-internal.example.com,并认为 NiFi 会拒绝其他主机值的请求,那就错了。NiFi 仅使用这些配置来了解哪些端口是有效的。

概念验证

服务器:apache-nifi-2.9.0-bin.zip以默认设置启动conf/nifi.properties(仅nifi.web.https.port=18443更改以释放默认端口)。单用户模式,HTTPS 已启用127.0.0.1:18443。

基线:

$ curl -sk --resolve localhost:18443:127.0.0.1 -H 'Accept: application/json' \\    https://localhost:18443/nifi-api/authentication/configuration{\"authenticationConfiguration\":{\"externalLoginRequired\":false,\"loginSupported\":true, \"loginUri\":\"https://localhost:18443/nf/#/login\", \"logoutUri\":\"https://localhost:18443/nifi-api/access/logout/complete\"}}

和X-Forwarded-Host:

$ curl -sk --resolve localhost:18443:127.0.0.1 -H 'Accept: application/json' \\    -H 'X-Forwarded-Host: attacker.example.com' \\    https://localhost:18443/nifi-api/authentication/configuration{\"authenticationConfiguration\":{\"externalLoginRequired\":false,\"loginSupported\":true, \"loginUri\":\"https://attacker.example.com:18443/nf/#/login\", \"logoutUri\":\"https://attacker.example.com:18443/nifi-api/access/logout/complete\"}}

和X-ProxyHost:

$ curl -sk --resolve localhost:18443:127.0.0.1 -H 'Accept: application/json' \\    -H 'X-ProxyHost: evil.example.com' \\    https://localhost:18443/nifi-api/authentication/configuration{\"authenticationConfiguration\":{\"externalLoginRequired\":false,\"loginSupported\":true, \"loginUri\":\"https://evil.example.com:18443/nf/#/login\", \"logoutUri\":\"https://evil.example.com:18443/nifi-api/access/logout/complete\"}}

值得注意的是:TLS 层 Host 头部得到了正确的控制。即使请求的Host: attacker.example.comSNI 匹配,也会被拒绝,Error 400 Invalid SNI因为 JettySecureRequestCustomizer强制执行了 SNI 对抗 Host 的机制。这种防御机制涵盖了 TLS 层 Host 头部。但它并不涵盖上面提到的两个 HTTP 应用层头部,而这两个头部正是 NiFi 前端的反向代理会从不受信任的客户端转发的头部。

下游

RequestUriBuilder.fromHttpServletRequest()在 NiFi 框架的 26 个站点中被调用。反射主机会遍历所有这些站点。安全关键型站点包括:

请求网站\t                            它所构建的StandardOAuth2AuthorizationRequestResolver.java:97\tredirect_uri已向 OIDC 身份提供商发送OAuth2请求StandardRelyingPartyRegistrationResolver.java:114\tAuthnRequest 中的 SAML SP 实体和 ACS URIOidcAuthenticationSuccessHandler.java:102, 105\tOIDC 重定向目标Saml2AuthenticationSuccessHandler.java:103, 106\tSAML重定向目标OidcLogoutSuccessHandler.java:213\tOIDC 注销后重定向目标StandardCookieCsrfTokenRepository.java:71\tCSRF cookie URI,用于推导 cookie 域AuthenticationResource.java:99\t匿名/nifi-api/authentication/configuration回复FlowResource.java:398, 2621\t内容查看器 URIApplicationResource.java:173, 187, 329\t用于集群复制的请求 URI

已验证的影响是匿名/authentication/configuration反射。值得关注的是 OAuth2 redirect\_uri。对于启用了 OIDC 的部署,redirect\_uri发送给身份提供商 (IdP) 的数据来自攻击者可控制的主机。如果 IdP 接受未注册的重定向 URI,或者对已注册的 URI 不进行通配符匹配(这种情况比您想象的要常见),攻击者就可以控制授权码的发送位置。这就是 5.4 版本中等影响的反射漏洞和 8.1 版本高影响的账户接管漏洞之间的区别。

它是如何来到这里的:NIFI-14209

提交ae5a77b84f5c7e5e51e85e99f1d40079dbdee5f1于 2025 年 2 月 5 日,标题为“重构主机头验证”。提交信息如下:

将 HostHeaderHandler 替换为 HostPortValidatorCustomizer。Jetty SecureRequestCustomizer 强制执行使用服务器证书 DNS 主题备用名称 (SNI) 的主机验证。添加了针对无效主机和端口值的 TLS SNI 的测试。重构并简化了 RequestUriBuilder.fromHttpServletRequest() 方法。

此次删除的差异代码HostHeaderHandler.java共 318 行,是 JettyHandler之前用于处理nifi.web.proxy.host列表并拒绝主机值超出列表范围的请求的代码。替换后的代码HostPortValidatorCustomizer.java共 85 行,仅用于验证端口。

前提是它SecureRequestCustomizer涵盖了通过 TLS SNI 进行的主机验证。这个前提对于 TLS 层的 Host 头部来说是正确的。但它并不适用于接下来读取的两个应用层头部(host 和X-Forwarded-Hosthost X-ProxyHost)StandardRequestUriProvider.getHost()。重构移动了信任边界,但没有更新另一侧的读取器。

受影响的版本

Apache NiFi 0.0.1 至 2.9.0 版本(根据官方公告,存在漏洞)

Apache NiFi 2.10.0(已修复)

引入此回归的 NIFI-14209 提交于 2025 年 2 月发布。2.2.0 之前的版本保留了原有的HostHeaderHandler防御机制;此回归是从该版本开始的。

修复

NiFi 2.10.0(Jira NIFI-15953,PR #11268)重新添加了允许列表验证,这次除了 Host 标头之外X-ProxyHost,还覆盖了其他标头。此修复与之前针对 context-path 标头的处理方式一致。公告文本如下:X-Forwarded-HostgetPath()

Apache NiFi 2.10.0 基于 nifi.web.proxy.host 属性实现了对 X-ProxyHost 和 X-Forwarded-Host HTTP 请求头的验证。启用请求头验证需要将应用程序配置为使用 HTTPS。位于 Apache NiFi 前端的反向代理服务器负责过滤输入请求头,并将允许的值提供给应用程序。

对于使用 2.2.0 到 2.9.0 版本且无法立即升级的运维人员,缓解措施是在反向代理上剥离这些标头X-Forwarded-Host,X-ProxyHost然后再将其传递到 NiFi。默认情况下nifi.properties不会对此发出警告;如果您在任何转发来自不受信任客户端的这些标头的服务器后运行 NiFi,请务必进行审计。

披露

已于 2026 年 5 月 15 日提交报告,[email protected]并附有上述实时复现步骤。Apache 方面迅速完成了漏洞分类和补丁开发。已分配 CVE 编号,PR 已合并,安全公告已于 2026 年 6 月 20 日发布。

链接

安全公告:https://nifi.apache.org/documentation/security/#CVE-2026-54665

CVE 记录:https://www.cve.org/CVERecord?id= CVE-2026-54665

NVD:https://nvd.nist.gov/vuln/detail/CVE-2026-54665

jira:https://issues.apache.org/jira/browse/NIFI-15953

修复 PR:https://github.com/apache/nifi/pull/11268

CWE-444:https://cwe.mitre.org/data/definitions/444.html

CWE-601:https://cwe.mitre.org/data/definitions/601.html

END

公众号内容都来自国外平台-所有文章可通过点击阅读原文到达原文地址或参考地址

排版 编辑 | Ots 小安

采集 翻译 | Ots Ai牛马

公众号 | AnQuan7 (Ots安全)


CVE-2026-54665:ApacheNiFi中的预认证主机头注入漏洞" 网络安全文章

CVE-2026-54665:ApacheNiFi中的预认证主机头注入漏洞"

CVE-2026-54665是ApacheNiFi中的预认证主机头注入漏洞,攻击者可通过X-Forwarded-Host或X-ProxyHost头操控OAuth2重定向URI等关键参数。该漏洞源于2025年重构时误删主机允许列表验证机制,影响0.0.1至2.9.0版本,在启用OIDC时可能导致账户接管(CVSS8.1)。官方已在2.10.0版本通过NIFI-15953修复,建议用户立即升级并验证代理配置。
借用AI对某软件去除卡密验证机制" 网络安全文章

借用AI对某软件去除卡密验证机制"

本文详细记录了通过AI辅助分析某软件卡密验证机制并实现绕过的完整过程。文章核心发现该软件使用PyInstaller打包,验证机制依赖服务端明文JSON响应且缺乏加密签名等安全防护,最终通过环境变量劫持API地址配合本地Mock服务器返回伪造成功响应实现绕过。关键可操作建议包括提取软件字符串锁定关键模块、分析验证流程弱点,并提供了完整的Python绕过脚本。
循环工程:教会AI智能体从自己的错误中学习" 网络安全文章

循环工程:教会AI智能体从自己的错误中学习"

循环工程是一种构建AI编程工作流的方法,通过规划、行动、观察、调整的持续迭代过程,使AI智能体能够从错误中学习并改进代码。该方法强调小步行动、可靠验证和明确停止规则,包含测试驱动、编译器驱动等五种常见模式。文章提出从狭窄任务开始、明确验证方法、人类参与判断等最佳实践,帮助团队实现安全高效的AI辅助编程。
爱迪生:揭露“发明大王”不为人知的一面" 网络安全文章

爱迪生:揭露“发明大王”不为人知的一面"

本文揭露爱迪生被神化形象背后的历史真相,指出其并非课本中描述的完美发明家,而是精于资本运作、打压竞争对手的商界霸主。文章通过分析电灯泡专利争议、为打压交流电当众电死大象、逼走电影人间接催生好莱坞等具体案例,展现其商业手段的冷酷与专利霸权的实质,旨在提供多元历史视角而非全盘否定其贡献。
评论:0   参与:  0