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

这是最初的问题。

我得到这个错误:

详细消息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());

当前回答

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

其他回答

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

cd %JAVA_HOME%/jre/lib/security/
scp cacerts mylinuxmachin:/tmp

然后在Linux机器上

cp /tmp/cacerts /etc/ssl/certs/java/cacerts

到目前为止,它工作得很好。

我正在使用颤振,却突然收到这个错误。基本上发生的是,在android/build中依赖项中的行。Gradle文件,如:

  classpath 'com.android.tools.build:gradle:4.1.0'
  classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

要求从网上下载成绩文件的证明。但是当有什么东西阻止gradle下载这些证书时,通常会显示这个。

I tried exporting the certificate and adding it manually but it didn't seem to work for me. What worked for me, after countless head scratches, was disabling the proxies from your network preferences. It was somewhere mentioned that disabling Charles Proxy would fix it but at that moment, I was clueless what Charles was and what proxy was. And in my case, I did not have the Charles proxy thing so I went on with finding the proxies in the network preferences settings in Mac( it could be found somewhere in network settings for Windows). I had Socks enabled within the proxy. I disabled it and then again rebuilt the gradle and TA-DAH!!! It worked butter smooth.

There are a few things to remember. If you build your project right after disabling proxy without closing the network preferences tab, the disable proxies won't work and it will show the same error. Also if you've already built the project and you're running it again after disabling proxies, chances are it's gonna show the same error( could be due to IDE caches). How it worked for me: Restart the Mac, open a few tabs in the browser( for a few network calls), check the network preferences from system preferences>> wifi and disable proxies, close the system preferences app, and build the project.

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

为了安全起见,我们不应该在实现中使用自签名证书。然而,当涉及到开发时,我们经常不得不使用获得自签名证书的试验环境。我试图在我的代码中以编程方式解决这个问题,但我失败了。但是,通过将证书添加到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");

希望这能有所帮助!

对于MacOS X,下面是我必须在'importcert'选项中尝试双连字符的确切命令,这是有效的:

sudo keytool -–importcert -file /PathTo/YourCertFileDownloadedFromBrowserLockIcon.crt -keystore /Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home/jre/lib/security/cacerts -alias "Cert" -storepass changeit