Maven 3.8.1 以上版本禁用 HTTP 仓库:原因与解决方法 – wiki基地


Maven 3.8.1+ 版本禁用 HTTP 仓库:原因与解决方法

软件开发的世界瞬息万变,安全性正日益成为所有环节中至关重要的一环。构建工具作为连接开发者与依赖库的桥梁,其安全性更是直接影响到整个软件供应链的安全。近年来,软件供应链攻击事件频发,例如 SolarWinds 事件等,都给业界敲响了警钟。在这样的背景下,Apache Maven 项目采取了一项重要举措:从 3.8.1 版本开始,默认禁用通过 HTTP 协议访问 Maven 仓库。

这项改变在当时给不少开发者和企业带来了困扰,许多原本正常工作的构建 suddenly failed (突然失败),错误信息指向无法下载依赖。本文旨在深入探讨 Maven 3.8.1 及以上版本为何要禁用 HTTP 仓库,以及遇到此类问题时应如何解决。

第一部分:为何禁用 HTTP 仓库?核心原因剖析

Maven 3.8.1 并非无缘无故地引入这项看似“破坏性”的改动。其背后是出于对软件供应链安全的深刻担忧和积极应对。HTTP 协议(超文本传输协议)在设计之初并未考虑如今复杂的网络环境和安全威胁,尤其是在传输敏感数据或构建关键资产(如软件依赖)时,使用 HTTP 存在以下几个核心安全风险:

  1. 缺乏加密(Lack of Encryption):

    • HTTP 协议在传输数据时是明文传输的,这意味着你的 Maven 客户端(例如你的电脑或构建服务器)与远程仓库服务器之间的所有通信内容,包括请求的依赖名称、版本以及下载的 Jar 包的原始数据,都以未加密的形式在网络中传输。
    • 在公共网络、不受信任的网络环境(如公共 Wi-Fi)甚至是被渗透的内网中,恶意攻击者可以轻易地通过网络嗅探工具(如 Wireshark)截获这些通信数据,获取你正在下载的依赖信息。
    • 更严重的是,攻击者可以直接看到并窃取下载的 Jar 包内容。尽管窃取 Jar 包本身可能不是最终目的,但结合其他攻击手段,可以获取敏感信息或分析你的项目结构。
  2. 缺乏完整性校验(Lack of Integrity Checking during Transit):

    • HTTP 协议本身不提供数据在传输过程中未被篡改的保证。虽然 Maven 在下载完成后会校验文件的 SHA1 或 SHA256 校验和(如果仓库提供了的话),但这只能验证文件 下载到本地后的完整性,而无法验证 文件在传输过程中 是否被篡改。
    • 想象一下,攻击者成功地劫持了你的 HTTP 连接,并在你下载 Jar 包的过程中偷偷替换了其中的代码(例如插入恶意后门)。由于 HTTP 缺乏传输层面的完整性保护,Maven 客户端在接收到篡改后的数据时,并不会发现异常,它会认为这就是服务器发送过来的数据。
    • 尽管 Maven 校验最终的校验和,但如果攻击者足够狡猾,不仅替换了 Jar 包,同时也替换了对应的校验和文件(.jar.sha1.jar.asc 等),Maven 的校验机制就会被绕过。这是典型的中间人攻击(Man-in-the-Middle, MITM)的一种方式。
  3. 容易遭受中间人攻击(Man-in-the-Middle Attacks):

    • 这是使用 HTTP 仓库最直接和最严重的风险之一。在你的 Maven 客户端和远程仓库之间,攻击者可以伪装成服务器与你通信,同时伪装成客户端与真实服务器通信。
    • 攻击者可以截获你对依赖的请求,并返回一个带有恶意代码的同名、同版本(甚至连文件大小和部分元数据都能伪造)的 Jar 包。由于 HTTP 不提供服务器身份验证机制(你无法确定连接到的服务器真的是你想连接的那个),你的 Maven 客户端会毫无戒心地下载并使用这个恶意依赖。
    • 一旦恶意依赖进入你的项目构建流程,它可能会被打包到你的最终产品中,或者在构建过程中执行恶意操作(例如窃取源代码、注入后门、破坏构建环境等)。这就是典型的软件供应链投毒攻击。
  4. 软件供应链投毒风险加剧:

    • 结合上述风险,HTTP 仓库为软件供应链投毒提供了便利条件。攻击者无需直接攻陷 Maven 仓库服务器本身,只需要能够截获或篡改你到仓库的网络连接,就能实现投毒。
    • 尤其是在企业内部,如果网络安全防护不到位,或者开发者使用了不受控的外部 HTTP 仓库,都可能成为攻击链上的薄弱环节。

为了对抗这些日益严重的威胁,行业标准和最佳实践都在向使用更安全的协议迁移。HTTPS(超文本传输安全协议)作为 HTTP 的安全版本,通过集成 TLS/SSL 协议,提供了数据加密、传输完整性校验和服务器身份验证等关键安全特性,能够有效地抵御上述风险。

Maven 3.8.1 默认禁用 HTTP 仓库,正是强制用户迁移到更安全的 HTTPS 环境,从而提高整个 Maven 生态系统和依赖其进行构建的软件项目的安全性。这项改变是必要的,尽管可能带来短期的不便。

第二部分:遇到 HTTP 仓库被禁用的问题现象

当 Maven 3.8.1 及以上版本尝试访问一个通过 http:// 开头的仓库地址时,构建通常会失败,并可能报告以下类型的错误信息:

  • 连接失败相关的错误,例如 ConnectException
  • Maven 自身的日志中可能会有关于 HTTP 禁用的警告或错误,提示仓库使用了不安全的协议。
  • 即使有时连接没有直接失败,下载依赖时也可能出现问题,因为 Maven 可能在内部阻止了不安全的请求。

例如,你可能会在构建日志中看到类似这样的信息:

[WARNING] Could not resolve artifact group.id:artifact-id:jar:version: Failure to find group.id:artifact-id:jar:version in https://repo.maven.apache.org/maven2 was cached in the local repository, resolution will not be reattempted until the update interval of central has elapsed or updates are forced. Original error: Could not transfer artifact group.id:artifact-id:jar:version from/to http://your-insecure-repo.com/maven (http://your-insecure-repo.com/maven): Blocked mirror for http://your-insecure-repo.com/maven.

或者更直接的连接错误:

Caused by: java.net.ConnectException: Connection refused (Connection refused)
at java.base/sun.nio.ch.Net.connect0(Native Method)
at java.base/sun.nio.ch.Net.connect(Net.java:576)
...

这些错误通常意味着 Maven 试图访问的某个仓库地址是 HTTP 的,并且被新版本的 Maven 阻止了。

第三部分:解决方法:如何应对 HTTP 仓库被禁用

面对 Maven 3.8.1+ 禁用了 HTTP 仓库的问题,有几种不同的解决方案,推荐程度和适用场景各不相同。

解决方案一:将仓库迁移到 HTTPS (强烈推荐,最佳实践)

这是从根本上解决问题的最佳方法,也是 Maven 团队推动此项改动的初衷。如果你的仓库(无论是公共仓库、第三方私有仓库还是企业内部仓库)支持 HTTPS,你应该立即切换到 HTTPS。

操作步骤:

  1. 修改 settings.xml 文件:

    • 这个文件通常位于 ~/.m2/settings.xml (用户级别) 或 ${maven.home}/conf/settings.xml (全局级别)。
    • 找到所有 <mirror><repository> 配置块,检查其 <url> 标签。
    • 如果 <url>http:// 开头,并且该仓库支持 HTTPS,将其更改为 https:// 开头。

    示例 (修改 <mirror>):

    xml
    <settings>
    ...
    <mirrors>
    <mirror>
    <id>my-company-nexus</id>
    <name>My Company Nexus</name>
    <url>https://nexus.mycompany.com/repository/maven-public/</url> <!-- 将 http 改为 https -->
    <mirrorOf>central,snapshots,internal-repo</mirrorOf>
    </mirror>
    <!-- 如果你直接引用某个第三方仓库 -->
    <!-- <mirror>
    <id>some-third-party</id>
    <url>https://some-third-party-repo.com/maven2/</url> // 确保这里是 https
    <mirrorOf>third-party-group</mirrorOf>
    </mirror> -->
    </mirrors>
    ...
    </settings>

    示例 (修改 <repository> – 一般不直接在 settings.xml 中配置第三方仓库,而是在 pom.xml 或通过 mirror):

    xml
    <!-- 谨慎在 settings.xml 中直接配置第三方 repository,通常通过 mirror 或在 pom.xml 中 -->
    <!-- 仅为演示如何修改 url -->
    <!--
    <settings>
    ...
    <profiles>
    <profile>
    <id>my-profile</id>
    <repositories>
    <repository>
    <id>my-internal-repo</id>
    <url>https://internal-repo.mycompany.com/maven2/</url> <!-- 将 http 改为 https -->
    <releases><enabled>true</enabled></releases>
    <snapshots><enabled>true</enabled></snapshots>
    </repository>
    </repositories>
    ...
    </profile>
    </profiles>
    ...
    </settings>
    -->

  2. 修改项目的 pom.xml 文件:

    • 如果你的项目 pom.xml 文件中直接定义了 <repository> 块(例如用于引用一些非中央仓库的第三方库或内部快照库),也需要检查并更新这些 URL 为 https://

    示例 (修改 <repository>pom.xml):

    xml
    <project>
    ...
    <repositories>
    <repository>
    <id>my-snapshot-repo</id>
    <url>https://internal-repo.mycompany.com/maven-snapshots/</url> <!-- 将 http 改为 https -->
    <releases><enabled>false</enabled></releases>
    <snapshots><enabled>true</enabled></snapshots>
    </repository>
    <!-- 如果引用了第三方仓库 -->
    <repository>
    <id>jsweet-central</id>
    <url>https://repository.jsweet.org/maven2/</url> <!-- 确保这里是 https -->
    </repository>
    </repositories>
    ...
    </project>

优势:

  • 提供了完整的安全保护(加密、完整性、身份验证)。
  • 是长期的、符合行业最佳实践的解决方案。
  • 一旦完成,可以充分利用 Maven 新版本带来的其他改进和功能。

劣势:

  • 如果目标仓库本身不支持 HTTPS,此方法无法直接应用。

解决方案二:使用安全的代理或镜像仓库 (推荐用于企业环境)

在企业环境中,通常推荐使用本地的 Maven 仓库管理器(如 Nexus Repository Manager 或 Artifactory)。这些仓库管理器可以配置为代理外部仓库(包括中央仓库和其他第三方仓库),并缓存下载的依赖。

你可以配置你的本地仓库管理器使用 HTTPS 对外提供服务,而由仓库管理器负责连接上游仓库。即使某些上游仓库只提供 HTTP,你的 Maven 客户端与本地仓库管理器之间的连接仍然是安全的 HTTPS。仓库管理器可以集中管理安全策略,例如对上游 HTTP 仓库进行额外的校验或过滤。

操作步骤:

  1. 搭建或配置企业内部的 Maven 仓库管理器 (如 Nexus 或 Artifactory)。
  2. 确保仓库管理器配置为通过 HTTPS 对外提供服务。 这通常涉及配置 SSL 证书。
  3. 在你的 Maven 客户端的 settings.xml 中,将所有的仓库请求都通过 <mirror> 指向这个内部的仓库管理器,并确保 mirror 的 URL 使用 HTTPS。

    示例 (settings.xml):

    xml
    <settings>
    ...
    <mirrors>
    <mirror>
    <id>nexus-internal</id>
    <name>My Company Nexus</name>
    <!-- Maven 客户端连接 Nexus 的地址,必须是 HTTPS -->
    <url>https://nexus.mycompany.com/repository/maven-public/</url>
    <mirrorOf>*</mirrorOf> <!-- 将所有仓库请求都导向 Nexus -->
    </mirror>
    </mirrors>
    ...
    </settings>

  4. 在仓库管理器中配置上游仓库。 即使某些上游配置为 HTTP,但因为你的 Maven 客户端只通过 HTTPS 连接到 Nexus,所以客户端层面的安全性得到了保证。

优势:

  • 将安全风险集中到可控的企业内部环境。
  • 提供了缓存、代理、私有仓库管理、用户权限控制等更多功能。
  • 即使部分上游仓库是 HTTP,客户端连接依然安全。
  • 符合企业级开发和构建的最佳实践。

劣势:

  • 需要额外搭建和维护仓库管理器服务。

解决方案三:临时绕过安全检查,允许 HTTP 仓库 (强烈不推荐,仅作临时救急)

如果你的构建因为某个确实不支持 HTTPS 的 HTTP 仓库而失败,并且你无法立即切换到 HTTPS 或搭建安全代理,作为临时应急方案,可以通过 Maven 的配置来绕过这个安全检查。

!!! 警告 !!!

使用此方法将重新暴露你的构建环境到前文所述的所有 HTTP 安全风险中(中间人攻击、投毒等)。这应该仅仅是作为临时解决方案,一旦条件允许,必须尽快迁移到 HTTPS 或使用安全代理。

Maven 3.8.1+ 禁用了 HTTP 的机制,一定程度上与 Maven 的代理配置 (<proxy>nonProxyHosts) 相关联。它阻止了直接通过 HTTP 连接仓库,除非目标主机被列在代理的 nonProxyHosts 中。利用这个特性,你可以通过设置 nonProxyHosts 来“欺骗”Maven,让它允许直接连接 HTTP 仓库。

操作步骤:

通过在 settings.xml<proxy> 配置中设置 nonProxyHosts*,可以绕过这个检查。即使你没有实际使用代理,添加一个空的或虚拟的 <proxy> 块并设置 nonProxyHosts 属性也可以达到目的。

  1. 修改 settings.xml 文件:

    • 找到或添加 <proxies> 标签。
    • <proxies> 标签内添加一个 <proxy> 块。
    • 在这个 <proxy> 块中,添加 <nonProxyHosts>*</nonProxyHosts>

    示例 (settings.xml):

    xml
    <settings>
    ...
    <proxies>
    <proxy>
    <id>allow-http</id>
    <active>true</active> <!-- 需要设置为 true 才能让 nonProxyHosts 生效 -->
    <protocol>http</protocol> <!-- 或者 https,不重要,关键是 nonProxyHosts -->
    <host>non-existent-host</host> <!-- 可以是任意值,因为 nonProxyHosts="*" 会绕过代理 -->
    <port>8080</port> <!-- 可以是任意值 -->
    <nonProxyHosts>*</nonProxyHosts> <!-- 关键设置:允许所有主机不通过代理,从而绕过 HTTP 限制 -->
    </proxy>
    </proxies>
    ...
    </settings>

    解释: Maven 3.8.1+ 的逻辑是:如果一个 HTTP URL 的主机不在当前活动代理的 nonProxyHosts 列表中,则阻止连接。通过将 nonProxyHosts 设置为 *,你告诉 Maven 所有的主机(包括你的 HTTP 仓库主机)都不需要通过代理,这绕过了那个特定的安全检查。

  2. 使用命令行参数 (更临时的方式):

    • 你也可以在执行 Maven 命令时,通过系统属性 -Dmaven.wagon.http.nonProxyHosts=* 来临时设置这个值。

    示例 (命令行):

    bash
    mvn clean install -Dmaven.wagon.http.nonProxyHosts=*

    解释: 这个系统属性会覆盖 settings.xml<proxy> 定义的 nonProxyHosts 值,效果相同。

风险:

  • 严重的安全漏洞: 这样做形同虚设了 Maven 3.8.1+ 为 HTTP 连接设置的安全屏障,你的构建再次面临中间人攻击和投毒的风险。
  • 仅为权宜之计: 这不是一个可持续的解决方案,仅仅是购买时间来实施真正的安全措施。

强烈建议: 如果你不得不使用这种方法,请立即制定计划,尽快将依赖的 HTTP 仓库迁移到 HTTPS,或者设置安全的代理/镜像仓库。一旦完成安全迁移,请立即移除 settings.xml 中的 <proxy> 块或停止使用命令行参数。

第四部分:总结与最佳实践

Maven 3.8.1 及以上版本默认禁用 HTTP 仓库是软件供应链安全背景下的一个重要且必要的改变。虽然可能短期内带来一些迁移成本,但从长远来看,它有助于提高整个开发和构建过程的安全性。

最佳实践总结:

  1. 优先迁移到 HTTPS: 检查并修改所有 settings.xmlpom.xml 文件中引用的仓库 URL,将其改为 https://。这是最直接、最安全的方式。
  2. 使用企业内部仓库管理器: 在企业环境中,强烈推荐搭建并使用 Nexus 或 Artifactory 等仓库管理器。通过 HTTPS 连接到内部仓库管理器,并让管理器处理对上游仓库的连接,可以提供更好的安全性、性能(缓存)和管理能力。
  3. 避免临时绕过: 尽量避免使用 nonProxyHosts=* 这种临时方案。如果实在需要,务必了解其风险,并将其视为必须立即解决的技术债。
  4. 定期审查依赖来源: 即使使用了 HTTPS,也要定期审查项目依赖的来源,确保它们来自可信的仓库,并关注依赖的安全漏洞报告。
  5. 升级 Maven 版本: 在解决完 HTTP 仓库问题后,应尽可能使用较新版本的 Maven,以获取更多的安全修复和功能改进。

通过积极拥抱 HTTPS,使用安全的仓库管理实践,我们可以显著降低软件供应链攻击的风险,构建更加安全可靠的软件产品。Maven 3.8.1 的这项改动,正是推动开发者和企业朝着这个方向迈出的重要一步。


发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部