编辑:我试图在我的博客上以更得体的方式格式化问题和接受的答案。

这是最初的问题。

我得到这个错误:

详细消息sun.security.validator.ValidatorException: PKIX路径 构建失败: provider.certpath. suncertpathbuilderexception:不能 找到请求目标的有效认证路径 导致javax.net.ssl.SSLHandshakeException: validatorexception: PKIX路径构建 失败:sun.security.provider.certpath.SunCertPathBuilderException: 无法找到请求目标的有效认证路径

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

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

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

选项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方法建议如何处理无效的SSL证书与Apache HttpClient?通过Pascal Thivent,即执行程序InstallCert。

但这种方法适用于开发盒设置,但我不能在生产环境中使用它。

我想知道为什么上面提到的三种方法都不工作,而我已经通过设置在App2服务器的server.xml中提到了相同的值,在truststore中也提到了相同的值

System.setProperty("javax.net.ssl.trustStore", "C:/.keystore")和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());

当前回答

我在Android Studio中得到这个错误。所以我做了很多研究之后。

“Password”为“changeit”

步骤1:以管理员身份打开CMD

第二步:输入Powershell

步骤3:start-process powershell -verb runas

步骤4:在C:\Program Files\Android\Android中添加所有的证书 Studio\jre\lib\security此位置是cacert可用的位置。

第五步:进入Keytool目录Set-Location -Path "C:\Program Files\Android\Android Studio\jre\bin"

第六步:在powershell中执行以下命令:\ keytool -importcert -trustcacerts -alias GiveNameforyourcertificate -file "C:\Program Files\Android\Android Studio\jre\lib\security\Replace With Your Certificate name. "Cer " -keystore cacerts

步骤7:如果错误出现为证书已添加(访问被拒绝),然后创建一个D驱动器分区(https://www.diskpart.com/windows-10/how-to-create-d-drive-from-c-drive-in-windows-10-0725.html)或移动您的文件到D驱动器,然后添加证书

如果你把文件保存在D盘,那么只执行这个

步骤8:keytool -importcert -trustcacerts -alias Nameyourcertificate -file "D:\Certificatename. txt "Cer " -keystore cacerts

\keytool -list -keystore cacerts . keystore cacerts . keystore - cacerts . keystore - cacerts . keystore - cacerts . keystore

其他回答

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

在我的例子中,问题是web服务器只发送证书和中间CA,而不是根CA。 添加这个JVM选项解决了这个问题:- dcom .sun.security. enableaiacaissuer =true

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

为了安全起见,我们不应该在实现中使用自签名证书。然而,当涉及到开发时,我们经常不得不使用获得自签名证书的试验环境。我试图在我的代码中以编程方式解决这个问题,但我失败了。但是,通过将证书添加到jre信任存储区,解决了我的问题。请参考以下步骤,

下载网站证书, 使用Chrome 用火狐 将证书(例如:cert_file.cer)复制到$JAVA_HOME\Jre\Lib\Security目录 在“管理员”中打开CMD,将目录更改为“$JAVA_HOME\Jre\Lib\Security” 使用以下命令将证书导入信任存储区,

keytool -import -alias ca -file cert_file.cer -keystore cacerts -商店通行证更改它

如果你得到一个错误说keytool是不可识别的,请参考这个。

键入yes,如下所示

信任此证书:[是]

现在尝试使用java以编程方式运行代码或访问URL。


更新

如果你的应用服务器是jboss,尝试添加下面的系统属性

System.setProperty("org.jboss.security.ignoreHttpsHost","true");

希望这能有所帮助!

这里似乎是记录臭名昭著的PKIX错误消息的另一个可能原因的好地方。在花了太长时间查看密钥库和信任库内容以及各种java安装配置之后,我意识到我的问题在于……一个错字。

输入错误意味着我还使用密钥存储库作为信任存储库。由于我的公司根CA没有被定义为keystore中的独立证书,而只是证书链的一部分,并且没有在其他任何地方定义(即cacerts),我一直得到PKIX错误。

在一次失败的发布之后(这是prod配置,在其他地方是可以的),经过两天的挠头,我终于看到了错别字,现在一切都好了。

希望这能帮助到一些人。

可以通过编程方式禁用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);

或者,如果您不控制下面的连接,您也可以为所有连接覆盖全局SSL验证https://stackoverflow.com/a/19542614/32453

如果你正在使用Apache HTTPClient,你必须“以不同的方式”禁用它:https://stackoverflow.com/a/2703233/32453