命令行工具
PKIX path building failed(Maven)下载依赖报错怎么修
Could not transfer artifact ... from/to central (https://repo.maven.apache.org/maven2): PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested targetMaven 报 PKIX path building failed,意思是运行 Maven 的 Java 环境不信任仓库出示的证书。 实际情况多半是公司代理用自己的根证书重新签发了 HTTPS,或者私有 Nexus、Artifactory 用的是内部 CA,而这张根证书不在 JDK 的 cacerts 里。它和 Java PKIX path building failed 是同一个问题,只是出现在构建工具里。
快速修复
最快的修法是把代理或内部 CA 的根证书导入 Maven 实际使用的那个 JDK。
- 找到 Maven 使用的 JDK:
mvn -v # 看 "Java home:" 一行
- 在这台机器上看仓库证书是谁签发的:
openssl s_client -connect maven.aliyun.com:443 -servername maven.aliyun.com -showcerts </dev/null | grep -E 's:|i:'
如果最上层的签发者是公司名或代理设备,而不是公网 CA,就找 IT 要这张根证书。
- 导入到那个 JDK:
"$JAVA_HOME/bin/keytool" -importcert -cacerts -alias company-proxy-root \
-file company-proxy-root.pem -storepass changeit -noprompt
(JDK 8 把 -cacerts 换成 -keystore "$JAVA_HOME/jre/lib/security/cacerts"。)然后重新构建。不需要清整个本地仓库,但要删掉下载失败时留下的 *.lastUpdated 文件,或者加 -U 运行。
原因
这个报错有 4 种原因,办公网络里最常见的是公司代理解密 HTTPS。
1. 公司代理或安全网关解密 HTTPS
浏览器正常,是因为 IT 把代理根证书装进了系统证书库;JDK 有自己的证书库,并不知道它。
- 确认: 所有 HTTPS 仓库都失败,签发者是代理设备。
- 修复: 按上面导入代理根证书;Windows 上也可以给 Maven 加
-Djavax.net.ssl.trustStoreType=Windows-ROOT,让 JDK 直接读 Windows 证书库。
2. 私有仓库用了内部 CA
公司自建的 Nexus、Artifactory 或 GitLab 制品库,证书由内部 CA 签发。
- 修复: 导入内部根证书,或者在项目里放一个专用信任库。先复制公网根证书,再加上自己的:
cp "$JAVA_HOME/lib/security/cacerts" .mvn/truststore.p12
keytool -importcert -keystore .mvn/truststore.p12 -storepass changeit \
-alias company-root -file company-root.pem -noprompt
然后在 .mvn/jvm.config 里写:
-Djavax.net.ssl.trustStore=.mvn/truststore.p12
-Djavax.net.ssl.trustStorePassword=changeit
3. 仓库服务器证书链不完整
自建 Nexus 前面放了 Nginx,只配置了站点证书,没发中间证书,浏览器能打开,Java 却报错。
- 确认:
openssl s_client -showcerts只列出一张证书,可以用证书链补全工具查看缺了哪张。 - 修复: 在服务器上配置完整证书链;宝塔面板里把中间证书一起粘贴到证书栏。
4. 修错了 JDK
导入到了一个 JDK,而 Maven、IDE 或 CI 构建机用的是另一个。逐一检查 mvn -v、IDE 的 Maven Runner 设置和 CI 镜像。
各环境修法
各环境的做法都是让运行 Maven 的 JVM 信任这张根证书:导入 cacerts,或者用参数指定专用信任库。
Maven Wrapper(mvnw)和 CI: 把信任库参数写进 .mvn/jvm.config 或 MAVEN_OPTS,每台构建机都能用上。用 Docker 镜像跑 CI 时,在构建镜像时就把根证书导入镜像里的 JDK。
国内镜像: 在 settings.xml 里配置阿里云等镜像(https://maven.aliyun.com/repository/public)可以加快下载,但它解决的是速度,不是信任问题;镜像地址也必须保持 https://。
IntelliJ IDEA / Eclipse: 确认运行 Maven 的 JDK(IDEA:Settings → Build Tools → Maven → Runner → JRE),导入到那个 JDK,或者改用已经修好的系统 JDK。
Gradle: 解析依赖时会报同样的错,在 gradle.properties 里指定信任库:
systemProp.javax.net.ssl.trustStore=/path/to/truststore.p12
systemProp.javax.net.ssl.trustStorePassword=changeit
Linux 系统自带 JDK: Debian/Ubuntu 和 CentOS/RHEL 系统上,把根证书加入系统信任库(update-ca-certificates 或 update-ca-trust)会同时更新系统 OpenJDK 的 cacerts。
不要这样做
关闭证书校验或改用 HTTP 仓库,都会让依赖下载失去防篡改保护。
-Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true之类的参数。它们关掉了依赖下载的证书校验,而依赖下载正是供应链攻击最常发生的地方。- 把仓库地址改成
http://,或者从settings.xml里删掉拦截 HTTP 的 mirror 配置。 - 提交包含私钥的信任库,或者从老 JDK 复制一份缺少新根证书的 cacerts。
常见问题
Maven 用的是哪个 JDK?
优先用 JAVA_HOME 指向的 JDK,没设置时用 PATH 上找到的 java。mvn -v 输出里的 Java home: 就是它。IntelliJ IDEA、Eclipse 可能用自己配置的 JDK 运行 Maven,那个 JDK 有自己的 cacerts。
能不能把信任库配置放在项目里,而不是每台电脑都改?
可以。Maven 3.3.1 起支持项目根目录的 .mvn/jvm.config,里面的 JVM 参数对每次构建生效,例如 -Djavax.net.ssl.trustStore=.mvn/truststore.p12。信任库里只能放证书,绝不能放私钥。
换成阿里云 Maven 镜像能解决吗?
只有当出问题的恰好是原来那台仓库服务器时才有用。如果是公司代理在解密 HTTPS,访问任何 HTTPS 地址都会同样报错,换镜像没有用,必须先让 JVM 信任代理根证书。
直接把仓库地址改成 http:// 不行吗?
不行。Maven 3.8.1 起默认拦截 HTTP 仓库,原因是:通过 HTTP 下载的依赖可以在传输途中被替换,而这些代码会进入你的构建和产品。