解决javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException:PKIX路径构建失败错误?

M S*_*ach 392 java ssl https

编辑: -尝试格式化问题并在我的博客中以更明显的方式接受答案

这是原始问题.

我收到此错误:

详细消息sun.security.validator.ValidatorException:PKIX路径构建失败:
sun.security.provider.certpath.SunCertPathBuilderException:无法找到请求目标的有效证书路径

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

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

keystoreFile="c:/.keystore" 
keystorePass="changeit"
Run Code Online (Sandbox Code Playgroud)

每个站点都说同样的原因,即app2提供的证书不在app1 jvm的可信存储中.当我试图在IE浏览器中访问相同的URL时,这似乎也是正确的,它可以工作(加热,这个网站的安全证书存在问题.在这里我说继续这个网站).但是当Java客户端(在我的情况下)遇到相同的URL时,我得到上述错误.所以把它放在信任库中我试过这三个选项:

选项1

System.setProperty("javax.net.ssl.trustStore", "C:/.keystore");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
Run Code Online (Sandbox Code Playgroud)

Option2 在环境变量中设置如下

CATALINA_OPTS -- param name
-Djavax.net.ssl.trustStore=C:\.keystore -Djavax.net.ssl.trustStorePassword=changeit ---param value
Run Code Online (Sandbox Code Playgroud)

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

JAVA_OPTS -- param name
-Djavax.net.ssl.trustStore=C:\.keystore -Djavax.net.ssl.trustStorePassword=changeit ---param value
Run Code Online (Sandbox Code Playgroud)

但没有任何效果.

最后工作的 是执行如何使用Apache HttpClient处理无效SSL证书中建议的Java方法由Pascal Thivent执行,即执行程序InstallCert.

但这种方法适用于devbox设置,但我无法在生产环境中使用它.

我很奇怪,为什么上面提到的三种方法时,我已经中提到的相同值没有工作server.xmlapp2服务器和相同的价值观信任设置

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());
Run Code Online (Sandbox Code Playgroud)

Sim*_*Sez 375

您需要将App2的证书添加到位于的已使用JVM的信任库文件中%JAVA_HOME%\lib\security\cacerts.

首先,您可以通过运行以下命令来检查您的证书是否已在信任库中:( keytool -list -keystore "%JAVA_HOME%/jre/lib/security/cacerts"您无需提供密码)

如果缺少证书,可以通过浏览器下载证书并使用以下命令将其添加到信任库:

keytool -import -noprompt -trustcacerts -alias <AliasName> -file <certificate> -keystore <KeystoreFile> -storepass <Password>

导入后,您可以再次运行第一个命令来检查您的证书是否已添加.

可以在此处找到Sun/Oracle信息.

  • 像SimonSez说的那样,你不需要密码,但如果你需要密码,默认密码是"changeit". (45认同)
  • 此外,在Windows中,您需要以管理员身份运行终端,否则在尝试导入证书时会收到错误"keytool error:java.io.FileNotFoundException ...(Access is denied)". (13认同)
  • 您必须使用完整路径,例如c:\ java\jdk\lib\security\cacerts (6认同)
  • 啊@SimonSez你是我的上帝.但要添加它,必须指定@M Sach提到的信任存储位置和密码才能使其工作. (2认同)
  • 继续遇到Java 1.8的问题.需要按照描述添加证书并使用Java <1.8 (2认同)
  • 即使添加证书后,我也收到相同的错误 (2认同)

NDe*_*per 172

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.在这方面,我必须提一下,我在谷歌的\ jre\lib \安全位置默认保留根证书信息 ,访问的默认密码是:changeit.

要查看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

输入密钥库密码:changeit

密钥库类型:jks

密钥库提供商:SUN

您的密钥库包含44个条目

verisignclass3g2ca,2004年3月26日,trustedCertEntry,

证书指纹(MD5):A2:33:9B:4C:74:78:73:D4:6C:E7:C1:F3:8D:CB:5C:E9

entrustclientca,2003年1月9日,trustedCertEntry,

证书指纹(MD5):0C:41:2F:13:5B:A0:54:F5:96:66:2D:7E:CD:0E:03:F4

thawtepersonalbasicca,1999年2月13日,trustedCertEntry,

证书指纹(MD5):E6:0B:D2:C9:CA:2D:88:DB:1A:71:0E:4B:78:EB:02:41

addtrustclass1ca,2006年5月1日,trustedCertEntry,

证书指纹(MD5):1E:42:95:02:33:92:6B:B9:5F:C0:7F:DA:D6:B2:4B:FC

verisignclass2g3ca,2004年3月26日,trustedCertEntry,

证书指纹(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文件中.

这是我在上面提到的Exception中找到的解决方案!!

  • +1用于虚拟友好指令 (50认同)
  • 有没有办法以编程方式执行此操作? (7认同)
  • 证书到期后你会怎么做?重复一切(每年)? (5认同)
  • 对于处理 PKIX 错误“路径不与任何信任锚链接”的人来说,不幸的是,这个解决方案并没有为我解决这个问题。 (3认同)
  • 一个问题 - aliasName是我们要导入证书的网址吗?例如,如果URL是http://domain.site.com/pages/service.asmx,那么别名应该是domain.site.com或完整的URL(domain.site.com/pages/service.asmx)或者它也应该是以http://为前缀或它只是一个任意名称? (3认同)
  • path:\lib\security&gt; keytool -import -noprompt -trustcacerts -alias webCert -file webCertResource.cer -keystore c:/Users/Jackie/Desktop -storepass changeit 我得到“系统找不到指定的文件” (2认同)

Jos*_*ush 36

如何在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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这就解决了我的问题:

1)下载.crt文件

echo -n | openssl s_client -connect <your domain>:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ~/<your domain>.crt
Run Code Online (Sandbox Code Playgroud)
  • 替换<your domain>您的域名(例如jossef.com)

2).crt在Java的cacerts证书库中应用该文件

keytool -import -v -trustcacerts -alias <your domain> -file ~/<your domain>.crt -keystore <JAVA HOME>/jre/lib/security/cacerts -keypass changeit -storepass changeit
Run Code Online (Sandbox Code Playgroud)
  • 替换<your domain>您的域名(例如jossef.com)
  • 替换<JAVA HOME>为您的java主目录

3)破解它

即使iv'e在我Java的默认证书存储中安装了我的证书,Tomcat也会忽略它(似乎它没有配置为使用Java的默认证书存储).

要破解这一点,请在代码中的某处添加以下内容:

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

// ...
Run Code Online (Sandbox Code Playgroud)

  • 第2步使用SpringBoot和Tomcat 7为我完成了窍门。谢谢。 (2认同)

Gui*_*ume 8

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

提供了对Authority Information Access扩展的caIssuers访问方法的支持。为了兼容性,默认情况下禁用此功能,可以通过将system属性设置为com.sun.security.enableAIAcaIssuerstrue 来启用它。

如果设置为true,则Sun的CertPathBuilder的PKIX实现将使用证书的AIA扩展名(除了指定的CertStores之外)中的信息来查找颁发CA证书,只要它是ldap,http或ftp类型的URI。

资源


Ali*_*lov 6

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

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

avp*_*avp 6

我正在使用 jdk1.8.0_171当我遇到同样的问题时,。我在这里尝试了前 2 个解决方案(使用 keytool 添加证书和另一个包含 hack 的解决方案),但它们对我不起作用。

我将我的 JDK 升级到1.8.0_181它,它就像一个魅力。


Rya*_*ton 5

我的cacerts文件完全是空的.我通过从我的Windows机器(使用Oracle Java 7)复制cacerts文件并将其scp到我的Linux机箱(OpenJDK)来解决这个问题.

cd %JAVA_HOME%/jre/lib/security/
scp cacerts mylinuxmachin:/tmp
Run Code Online (Sandbox Code Playgroud)

然后在linux机器上

cp /tmp/cacerts /etc/ssl/certs/java/cacerts
Run Code Online (Sandbox Code Playgroud)

到目前为止它运作良好.


Ced*_*mon 5

在Linux下使用Tomcat 7可以达到目的。

String certificatesTrustStorePath = "/etc/alternatives/jre/lib/security/cacerts";
System.setProperty("javax.net.ssl.trustStore", certificatesTrustStorePath);
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
Run Code Online (Sandbox Code Playgroud)

在Linux下,$JAVA_HOME并非总是设置,但通常/etc/alternatives/jre指向$JAVA_HOME/jre


YaD*_*aDa 5

对我来说,尝试连接到正在处理SSL的NGINX反向代理背后的进程时,也会出现此错误。

原来,问题出在没有整个证书链串联的证书。当我添加中间证书时,问题就解决了。

希望这可以帮助。


小智 5

下面的代码为我工作:

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 new X509Certificate[] {};
}
}
Run Code Online (Sandbox Code Playgroud)
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());  

             conn.setSSLSocketFactory(sc.getSocketFactory());
Run Code Online (Sandbox Code Playgroud)

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

Bah*_*mir 5

可部署的解决方案(Alpine Linux)

为了能够在我们的应用程序环境中解决此问题,我们准备了 Linux 终端命令,如下所示:

cd ~
Run Code Online (Sandbox Code Playgroud)

将在主目录中生成证书文件。

apk add openssl
Run Code Online (Sandbox Code Playgroud)

此命令在 alpine Linux 中安装 openssl。您可以找到适用于其他 Linux 发行版的正确命令。

openssl s_client -connect <host-dns-ssl-belongs> < /dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > public.crt
Run Code Online (Sandbox Code Playgroud)

生成了所需的证书文件。

sudo $JAVA_HOME/bin/keytool -import -alias server_name -keystore $JAVA_HOME/lib/security/cacerts -file public.crt -storepass changeit -noprompt
Run Code Online (Sandbox Code Playgroud)

使用程序“keytool”将生成的文件应用到 JRE。

注意:请将您的 DNS 替换为<host-dns-ssl-belongs>

注意2:请轻轻注意,-noprompt不会提示验证消息(是/否),并且-storepass changeit参数将禁用密码提示并提供所需的密码(默认为“changeit”)。这两个属性将允许您在应用程序环境中使用这些脚本,例如构建 Docker 映像。

注3如果您通过 Docker 部署应用程序,您可以生成一次机密文件并将其放入您的应用程序项目文件中。您不需要一次又一次地生成它。


归档时间:

查看次数:

1006875 次

最近记录:

5 年,11 月 前