问答中心分类: JAVA解决 javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed 错误?
0
匿名用户 提问 17分钟 前

编辑 :我试图以更体面的方式格式化问题并接受答案博客.
这是原始问题。
我收到此错误:

详细信息 sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException:无法找到请求目标的有效证书路径
导致 javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException:PKIX 路径构建失败:sun.security.provider.certpath.SunCertPathBuilderException:无法找到请求目标的有效证书路径

我使用 Tomcat 6 作为网络服务器。我在不同端口上的不同 Tomcat 上安装了两个 HTTPS Web 应用程序,但在同一台机器上。说 App1(端口 8443)和 App2(端口 443)。 App1 连接到 App2。当 App1 连接到 App2 时,出现上述错误。我知道这是一个非常常见的错误,因此在不同的论坛和网站上遇到了许多解决方案。我有以下条目server.xml两个Tomcat:

keystoreFile="c:/.keystore" 
keystorePass="changeit"

每个站点都说app2提供的证书不在app1 jvm的受信任存储中的原因相同。当我尝试在 IE 浏览器中点击相同的 URL 时,这似乎也是如此,它可以工作(随着变暖,这个网站的安全证书有问题。这里我说继续这个网站)。但是,当 Java 客户端(在我的情况下)点击相同的 URL 时,我得到了上述错误。因此,为了把它放在信任库中,我尝试了以下三个选项:
选项1

System.setProperty("javax.net.ssl.trustStore", "C:/.keystore");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");

选项 2
在环境变量中设置以下

CATALINA_OPTS -- param name
-Djavax.net.ssl.trustStore=C:\.keystore -Djavax.net.ssl.trustStorePassword=changeit ---param value

选项 3
在环境变量中设置以下

JAVA_OPTS -- param name
-Djavax.net.ssl.trustStore=C:\.keystore -Djavax.net.ssl.trustStorePassword=changeit ---param value

结果
但没有任何效果。
什么终于奏效了正在执行中建议的 Java 方法如何使用 Apache HttpClient 处理无效的 SSL 证书?通过 Pascal Thivent 即执行程序 InstallCert。
但是这种方法适用于 devbox 设置,但我不能在生产环境中使用它。
我想知道为什么上面提到的三种方法在我提到相同的值时不起作用server.xml通过设置 App2 服务器和信任库中的相同值
System.setProperty("javax.net.ssl.trustStore", "C:/.keystore") and System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
在 App1 程序中。
有关更多信息,这是我建立连接的方式:

URL url = new URL(urlStr);

URLConnection conn = url.openConnection();

if (conn instanceof HttpsURLConnection) {

  HttpsURLConnection conn1 = (HttpsURLConnection) url.openConnection();
  
  conn1.setHostnameVerifier(new HostnameVerifier() {
    public boolean verify(String hostname, SSLSession session) {
      return true;
    }
  });

  reply.load(conn1.getInputStream());
user207421 回复 17分钟 前

可能的重复HttpClient 和 SSL

user207421 回复 17分钟 前

奇怪的是,我在单独没有 SSL 问题的集群服务器之间进行通信时遇到了这个错误。一旦我正确设置domainname在我的 RHEL 服务器中,问题消失了。希望它可以帮助某人。

user207421 回复 17分钟 前

要检查的另一件事是您是否拥有最新版本的 Java – 因此我遇到了类似的错误。

user207421 回复 17分钟 前

stackoverflow.com/questions/2893819/…– 也是相关且出色的答案。

user207421 回复 17分钟 前

首先将您的 crt 文件导入 {JAVA_HOME}/jre/security/cacerts,如果您仍然遇到此异常,请更改您的 jdk 版本。例如从 jdk1.8.0_17 到 jdk1.8.0_231

user207421 回复 17分钟 前

我在Windows中遇到了这个问题,我在这里找到了答案:stackoverflow.com/questions/41257366/…

29 Answers
0
NDeveloper 回答 17分钟 前

javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException:PKIX 路径构建失败:sun.security.provider.certpath.SunCertPathBuilderException:无法找到请求目标的有效证书路径

• 当我收到错误消息时,我尝试用谷歌搜索该表达式的含义,我发现,当服务器更改其 HTTPS SSL 证书并且我们的旧版 java 无法识别根证书颁发机构 (CA) 时,会出现此问题.
• 如果您可以在浏览器中访问 HTTPS URL,则可以更新 Java 以识别根 CA。
• 在您的浏览器中,转到Java 无法访问的HTTPS URL。点击 HTTPS 证书链(Internet Explorer 中有锁图标),点击锁查看证书。
• 转到证书的“详细信息”和“复制到文件”。复制进去Base64 (.cer)格式。它将保存在您的桌面上。
• 安装证书忽略所有警报。
• 这就是我收集我试图访问的 URL 的证书信息的方式。
现在我必须让我的 java 版本知道证书,这样它就不会拒绝识别 URL。在这方面,我必须提到,我在谷歌上搜索到根证书信息默认保留在 JDK 的\jre\lib\security位置,访问的默认密码是:更改。
要查看 cacerts 信息,请遵循以下步骤:
• 单击开始按钮–>运行
• 键入 cmd。命令提示符打开(您可能需要以管理员身份打开它)。
• 转到您的Java/jreX/bin目录
• 键入以下内容

keytool -list -keystore D:\Java\jdk1.5.0_12\jre\lib\security\cacerts

它给出了包含在密钥库中的当前证书的列表。它看起来像这样:

C:\Documents and Settings\NeelanjanaG>keytool -list -keystore D:\Java\jdk1.5.0_12\jre\lib\security\cacerts

Enter keystore password:  changeit

Keystore type: jks

Keystore provider: SUN

Your keystore contains 44 entries

verisignclass3g2ca, Mar 26, 2004, trustedCertEntry,

Certificate fingerprint (MD5): A2:33:9B:4C:74:78:73:D4:6C:E7:C1:F3:8D:CB:5C:E9

entrustclientca, Jan 9, 2003, trustedCertEntry,

Certificate fingerprint (MD5): 0C:41:2F:13:5B:A0:54:F5:96:66:2D:7E:CD:0E:03:F4

thawtepersonalbasicca, Feb 13, 1999, trustedCertEntry,

Certificate fingerprint (MD5): E6:0B:D2:C9:CA:2D:88:DB:1A:71:0E:4B:78:EB:02:41

addtrustclass1ca, May 1, 2006, trustedCertEntry,

Certificate fingerprint (MD5): 1E:42:95:02:33:92:6B:B9:5F:C0:7F:DA:D6:B2:4B:FC

verisignclass2g3ca, Mar 26, 2004, trustedCertEntry,

Certificate fingerprint (MD5): F8:BE:C4:63:22:C9:A8:46:74:8B:B8:1D:1E:4A:2B:F6

• 现在我必须将以前安装的证书包含在 cacerts 中。
• 为此,程序如下:

keytool -import -noprompt -trustcacerts -alias ALIASNAME -file FILENAME_OF_THE_INSTALLED_CERTIFICATE -keystore PATH_TO_CACERTS_FILE -storepass PASSWORD

如果您使用的是 Java 7:

keytool -importcert -trustcacerts -alias ALIASNAME -file PATH_TO_FILENAME_OF_THE_INSTALLED_CERTIFICATE -keystore PATH_TO_CACERTS_FILE -storepass changeit

• 然后它将证书信息添加到 cacert 文件中。
这是我为上述异常找到的解决方案!!

ggkmath 回复 17分钟 前

证书过期了怎么办?重复一切(每年)?

JBA 回复 17分钟 前

考虑使用有效期更长的证书?就像 50 年的测试;)

moomoohk 回复 17分钟 前

有没有办法以编程方式做到这一点?

IcedDante 回复 17分钟 前

对于处理 PKIX 错误“路径不与任何信任锚链接”的人来说,不幸的是,这个解决方案并没有解决这个问题。

nanosoft 回复 17分钟 前

一个问题 – aliasName 是我们为其导入证书的网址吗?例如,如果 URL 是domain.site.com/pages/service.asmx那么别名应该是 domain.site.com 或完整的 URL(domain.site.com/pages/service.asmx) 还是应该以 http:// 为前缀,或者它只是一个任意名称?

Dowlers 回复 17分钟 前

@IcedD​​ante 你有没有找到解决方案?我也有同样的问题。

Farooque 回复 17分钟 前

当我从水槽调用 Twitter 源时,我遇到了同样的错误。我的 jdk 版本是 1.8.0_45。因为我有最新的 jdk,可能是什么问题?

JayC 回复 17分钟 前

路径:\lib\security> keytool -import -noprompt -trustcacerts -alias webCert -file webCertResource.cer -keystore c:/Users/Jackie/Desktop -storepass changeit 我得到“系统找不到指定的文件”

Yampeku 回复 17分钟 前

如果您收到错误 @Jesse 只需确保您以管理员权限运行 cmd

Augusto 回复 17分钟 前

很好,很好,很好,很好!

notPercival 回复 17分钟 前

这对我没有用,第二天突然就用了,所以也许你需要关闭你的 JVM/PC 并再试一次

memoricab 回复 17分钟 前

这对我有用,我收到 PKIX 错误

Anggrayudi H 回复 17分钟 前

供参考,cacertsMacOS 上的 Android Studio 文件位于/Applications/Android Studio.app/Contents/jre/Contents/Home/lib/security

0
Jossef Harush Kadouri 回答 17分钟 前

如何在 Tomcat 7 中工作
我想在 Tomcat 应用程序中支持自签名证书,但是以下代码段无法正常工作

import java.io.DataOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class HTTPSPlayground {
    public static void main(String[] args) throws Exception {

        URL url = new URL("https:// ... .com");
        HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();

        httpURLConnection.setRequestMethod("POST");
        httpURLConnection.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
        httpURLConnection.setDoOutput(true);
        DataOutputStream wr = new DataOutputStream(httpURLConnection.getOutputStream());

        String serializedMessage = "{}";
        wr.writeBytes(serializedMessage);
        wr.flush();
        wr.close();

        int responseCode = httpURLConnection.getResponseCode();
        System.out.println(responseCode);
    }
}

这就是解决我的问题的方法:
1) 下载.crt文件

echo -n | openssl s_client -connect :443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ~/.crt
  • 代替使用您的域(例如jossef.com)

2) 应用.crtJava中的文件cacerts证书存储

keytool -import -v -trustcacerts -alias  -file ~/.crt -keystore /jre/lib/security/cacerts -keypass changeit -storepass changeit
  • 代替使用您的域(例如jossef.com)
  • 代替使用您的 java 主目录

3)破解它
即使我已经安装了我的证书Java的默认证书存储,Tomcat忽略了这一点(似乎它没有配置为使用 Java 的默认证书存储)。
要解决这个问题,请在代码中的某处添加以下内容:

String certificatesTrustStorePath = "/jre/lib/security/cacerts";
System.setProperty("javax.net.ssl.trustStore", certificatesTrustStorePath);

// ...
Tim Perry 回复 17分钟 前

第 2 步使用 SpringBoot 和 Tomcat 7 为我解决了问题。谢谢。

vikifor 回复 17分钟 前

我必须使用tomcat使用的java中的keytool吗?因为在一台服务器上我可以有很多java

Jossef Harush Kadouri 回复 17分钟 前

@vikifor 是的。您还可以为系统上安装的所有 java 目录运行它

prayagupa 回复 17分钟 前

我明白了Keystore was tampered with, or password was incorrect导入时出错.crt

Jossef Harush Kadouri 回复 17分钟 前

@prayagupd – 也许商店密码不同?默认密码是changeit.看stackoverflow.com/q/16891182/3191896

Tom Taylor 回复 17分钟 前

这行得通!非常感谢@JossefHarush 提供了如此有用的答案!

Chamod Pathirana 回复 17分钟 前

将@Jossef Harush 的代码段添加到我的代码中后,我的问题得到了解决。

Sergio 回复 17分钟 前

@JossefHarush 非常感谢您发布此信息!它就像一个魅力!

0
Guillaume 回答 17分钟 前

在我的情况下,问题是网络服务器只发送证书和中间 CA,而不是根 CA。添加这个 JVM 选项解决了这个问题:-Dcom.sun.security.enableAIAcaIssuers=true

提供对权威信息访问扩展的 caIssuers 访问方法的支持。为了兼容性,它默认是禁用的,可以通过设置系统属性来启用com.sun.security.enableAIAcaIssuers为真值。
如果设置为 true,则 Sun 的 CertPathBuilder 的 PKIX 实现使用证书的 AIA 扩展中的信息(除了指定的 CertStores)来查找颁发的 CA 证书,前提是它是 ldap、http 或 ftp 类型的 URI。

资源

0
Ali Ismayilov 回答 17分钟 前

另一个原因可能是 JDK 版本过时。我使用的是 jdk 版本 1.8.0_60,只需更新到最新版本即可解决证书问题。

hertg 回复 17分钟 前

我也有同样的问题。使用 Lets Encrypt 证书调用 API 可能不适用于旧版本的 Java,因为受信任的根证书颁发机构无法识别它。更新 Java 将解决此问题。

0
Sandip S. 回答 17分钟 前

可以通过编程方式禁用 SSL 验证。在开发人员的紧要关头工作,但不推荐用于生产,因为您需要在那里使用“真实”SSL 验证,或者安装并使用您自己的受信任密钥,然后仍然使用“真实”SSL 验证。
下面的代码对我有用:

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;

public class TrustAnyTrustManager implements X509TrustManager {

  public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
  }

  public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
  }

  public X509Certificate[] getAcceptedIssuers() {
    return null;
  }
}
HttpsURLConnection conn = null;
             URL url = new URL(serviceUrl);
             conn = (HttpsURLConnection) url.openConnection();
             SSLContext sc = SSLContext.getInstance("SSL");  
             sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom());  
                    // Create all-trusting host name verifier
             HostnameVerifier allHostsValid = new HostnameVerifier() {
               public boolean verify(String hostname, SSLSession session) {
                return true;
              }
            };
            conn.setHostnameVerifier(allHostsValid);

或者如果你不控制Connection在下面,您还可以为所有连接全局覆盖 SSL 验证https://stackoverflow.com/a/19542614/32453
如果您使用的是 Apache HTTPClient,则必须“以不同方式”禁用它(遗憾的是):https://stackoverflow.com/a/2703233/32453

user207421 回复 17分钟 前

此代码完全不安全,不应使用。

Govinda Sakhare 回复 17分钟 前

@user207421 为什么它不安全?代码中发生了什么简要说明。

Scott Taylor 回复 17分钟 前

这是跳过所有证书验证,基本上它允许接受任何证书。证书的工作方式是在各个认证机构都有一个根证书(字面意思)受到物理保护。然后使用该证书颁发其他二级证书,这些二级证书可以一直验证到根证书颁发机构。这将跳过所有上游检查,这意味着我可以发送任何 ssl 证书(甚至是自己生成的),并且您的应用程序将接受它是安全的,即使我作为 url 的身份未经过验证。