如何解决 javax.net.ssl.SSLHandshakeException 错误?

发布于 2024-11-19 16:51:20 字数 403 浏览 3 评论 0原文

我通过 VPN 连接来设置库存 API 来获取产品列表,效果很好。一旦我从网络服务获得结果并绑定到用户界面。而且我将 PayPal 与我的应用程序集成在一起,以便在我拨打电话付款时进行快速结帐,但我遇到了此错误。我使用 servlet 进行后端处理。任何人都可以说如何解决这个问题吗?

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: 
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target

I connected with VPN to setup the inventory API to get product list and it works fine. Once I get the result from the web-service and i bind to UI. And also I integrated PayPal with my application for make Express checkout when I make a call for payment I'm facing this error. I use servlet for back-end process. Can any one say how to fix this issue?

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: 
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

弱骨蛰伏 2024-11-26 16:51:21

这是我使用最新的 JDK 11 HttpClient 将 JSON 发布到具有不安全/无效 SSL 证书的 URL 所做的操作:

    // Create a trust manager that does not validate certificate chains
    TrustManager[] trustAllCerts = new TrustManager[]{
            new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                public void checkClientTrusted(
                        java.security.cert.X509Certificate[] certs, String authType) {
                }
                public void checkServerTrusted(
                        java.security.cert.X509Certificate[] certs, String authType) {
                }
            }
    };

    try {

        // Install the all-trusting trust manager
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

        // Creat HttpClient with new SSLContext.
        HttpClient httpClient = HttpClient.newBuilder()
                .connectTimeout(Duration.ofMillis(3 * 1000))
                .sslContext(sc) // SSL context 'sc' initialised as earlier
                .build();

        // Create request.
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(<URL>))
                .timeout(Duration.ofMinutes(1))
                .header("Content-Type", "application/json")
                .header("Accept", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(<PAYLOAD JSON STRING>))
                .build();

        //Send Request
        HttpResponse<String> response =
                httpClient.send(request, HttpResponse.BodyHandlers.ofString());

        //Access response JSON
        String responseJson = response.body();

   } catch (Exception e) {
     throw new Exception(e);
   }

This is what I did to POST a JSON to a URL with insecure/invalid SSL certs using latest JDK 11 HttpClient:

    // Create a trust manager that does not validate certificate chains
    TrustManager[] trustAllCerts = new TrustManager[]{
            new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                public void checkClientTrusted(
                        java.security.cert.X509Certificate[] certs, String authType) {
                }
                public void checkServerTrusted(
                        java.security.cert.X509Certificate[] certs, String authType) {
                }
            }
    };

    try {

        // Install the all-trusting trust manager
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

        // Creat HttpClient with new SSLContext.
        HttpClient httpClient = HttpClient.newBuilder()
                .connectTimeout(Duration.ofMillis(3 * 1000))
                .sslContext(sc) // SSL context 'sc' initialised as earlier
                .build();

        // Create request.
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(<URL>))
                .timeout(Duration.ofMinutes(1))
                .header("Content-Type", "application/json")
                .header("Accept", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(<PAYLOAD JSON STRING>))
                .build();

        //Send Request
        HttpResponse<String> response =
                httpClient.send(request, HttpResponse.BodyHandlers.ofString());

        //Access response JSON
        String responseJson = response.body();

   } catch (Exception e) {
     throw new Exception(e);
   }
一曲爱恨情仇 2024-11-26 16:51:20

首先,您需要从您尝试连接的服务器获取公共证书。这可以通过多种方式完成,例如联系服务器管理员并询问,使用 OpenSSL 下载它,或者,因为这似乎是一个 HTTP 服务器,所以使用任何浏览器连接到它,查看页面的安全信息,并保存证书的副本。 (Google 应该能够准确地告诉您针对特定浏览器要做什么。)

现在您已将证书保存在文件中,您需要将其添加到 JVM 的信任存储中。在 JRE 的 $JAVA_HOME/jre/lib/security/ 或 JDK 的 $JAVA_HOME/lib/security 中,有一个名为 cacerts 的文件,该文件Java 附带并包含知名认证机构的公共证书。要导入新证书,请以有权写入 cacerts 的用户身份运行 keytool:

keytool -import -file <the cert file> -alias <some meaningful name> -keystore <path to cacerts file>

它很可能会要求您输入密码。 Java 附带的默认密码是 changeit。几乎没有人改变它。完成这些相对简单的步骤后,您将可以安全地进行通信,并确保您正在与正确的服务器且仅与正确的服务器通信(只要他们不丢失私钥)。

First, you need to obtain the public certificate from the server you're trying to connect to. That can be done in a variety of ways, such as contacting the server admin and asking for it, using OpenSSL to download it, or, since this appears to be an HTTP server, connecting to it with any browser, viewing the page's security info, and saving a copy of the certificate. (Google should be able to tell you exactly what to do for your specific browser.)

Now that you have the certificate saved in a file, you need to add it to your JVM's trust store. At $JAVA_HOME/jre/lib/security/ for JREs or $JAVA_HOME/lib/security for JDKs, there's a file named cacerts, which comes with Java and contains the public certificates of the well-known Certifying Authorities. To import the new cert, run keytool as a user who has permission to write to cacerts:

keytool -import -file <the cert file> -alias <some meaningful name> -keystore <path to cacerts file>

It will most likely ask you for a password. The default password as shipped with Java is changeit. Almost nobody changes it. After you complete these relatively simple steps, you'll be communicating securely and with the assurance that you're talking to the right server and only the right server (as long as they don't lose their private key).

暖风昔人 2024-11-26 16:51:20

每当我们尝试连接到 URL 时,

如果另一个站点的服务器正在 https 协议上运行,并且要求我们应该通过证书中提供的信息进行通信,那么
我们有以下选项:

1)请求证书(下载证书),将此证书导入到trustore中。 java使用的默认trustore可以在\Java\jdk1.6.0_29\jre\lib\security\cacerts中找到,那么如果我们重试连接该URL连接就会被接受。

2) 在正常业务情况下,我们可能会连接到组织中的内部 URL,并且我们知道它们是正确的。
在这种情况下,您相信它是正确的 URL。在上述情况下,可以使用不强制存储证书以连接到特定 URL 的代码。

对于第 2 点,我们必须遵循以下步骤:

1)编写以下方法,为 HttpsURLConnection 设置 HostnameVerifier,该方法在所有情况下返回 true,这意味着我们信任 trustStore。

  // trusting all certificate 
 public void doTrustToCertificates() throws Exception {
        Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
        TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    public X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }

                    public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        return;
                    }

                    public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        return;
                    }
                }
        };

        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HostnameVerifier hv = new HostnameVerifier() {
            public boolean verify(String urlHostName, SSLSession session) {
                if (!urlHostName.equalsIgnoreCase(session.getPeerHost())) {
                    System.out.println("Warning: URL host '" + urlHostName + "' is different to SSLSession host '" + session.getPeerHost() + "'.");
                }
                return true;
            }
        };
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
    }

2) 编写下面的方法,在尝试连接 URL 之前调用 doTrustToCertificates

    // connecting to URL
    public void connectToUrl(){
     doTrustToCertificates();//  
     URL url = new URL("https://www.example.com");
     HttpURLConnection conn = (HttpURLConnection)url.openConnection(); 
     System.out.println("ResponseCode ="+conn.getResponseCode());
   }

此调用将返回响应代码 = 200 表示连接成功。

有关更多详细信息和示例示例,您可以参考 网址

Whenever we are trying to connect to URL,

if server at the other site is running on https protocol and is mandating that we should communicate via information provided in certificate then
we have following option:

1) ask for the certificate(download the certificate), import this certificate in trustore. Default trustore java uses can be found in \Java\jdk1.6.0_29\jre\lib\security\cacerts, then if we retry to connect to the URL connection would be accepted.

2) In normal business cases, we might be connecting to internal URLS in organizations and we know that they are correct.
In such cases, you trust that it is the correct URL, In such cases above, code can be used which will not mandate to store the certificate to connect to particular URL.

for the point no 2 we have to follow below steps :

1) write below method which sets HostnameVerifier for HttpsURLConnection which returns true for all cases meaning we are trusting the trustStore.

  // trusting all certificate 
 public void doTrustToCertificates() throws Exception {
        Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
        TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    public X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }

                    public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        return;
                    }

                    public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        return;
                    }
                }
        };

        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HostnameVerifier hv = new HostnameVerifier() {
            public boolean verify(String urlHostName, SSLSession session) {
                if (!urlHostName.equalsIgnoreCase(session.getPeerHost())) {
                    System.out.println("Warning: URL host '" + urlHostName + "' is different to SSLSession host '" + session.getPeerHost() + "'.");
                }
                return true;
            }
        };
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
    }

2) write below method, which calls doTrustToCertificates before trying to connect to URL

    // connecting to URL
    public void connectToUrl(){
     doTrustToCertificates();//  
     URL url = new URL("https://www.example.com");
     HttpURLConnection conn = (HttpURLConnection)url.openConnection(); 
     System.out.println("ResponseCode ="+conn.getResponseCode());
   }

This call will return response code = 200 means connection is successful.

For more detail and sample example you can refer to URL.

初心未许 2024-11-26 16:51:20

我相信您正在尝试使用 SSL 连接到某个东西,但该东西提供的证书未经根证书颁发机构(例如 verisign)验证。本质上,默认情况下,只有在尝试连接的人知道的情况下才能建立安全连接交易对手密钥或其他一些验证者(例如威瑞信)可以介入并说所提供的公钥确实是正确的。

所有操作系统都信任少数认证机构,而较小的证书颁发者需要由大型认证机构之一进行认证链的验证者,如果你明白我的意思的话......

无论如何,回到正题......我在编写java小程序和java服务器时遇到了类似的问题(希望有一天我会写一篇完整的博客文章,讲述我如何获得所有安全性工作:))

本质上我要做的就是从服务器中提取公钥并将其存储在我的小程序内的密钥库中,当我连接到服务器时,我使用这个密钥库来创建一个信任工厂和该信任工厂创建 ssl 联系。还有一些替代过程,例如将密钥添加到 JVM 的受信任主机并在启动时修改默认信任存储。

我大约两个月前做了这件事,现在我身上没有源代码。使用 google,你应该能够解决这个问题。如果您无法给我回复消息,我可以为您提供该项目的相关源代码..不知道这是否可以解决您的问题,因为您没有提供导致这些异常的代码。此外,我正在使用小程序,我想我不明白为什么它不能在 Serverlet 上工作...

PS 我无法在周末之前获得源代码,因为我的办公室禁用了外部 SSH :(

I believe that you are trying to connect to a something using SSL but that something is providing a certificate which is not verified by root certification authorities such as verisign.. In essence by default secure connections can only be established if the person trying to connect knows the counterparties keys or some other verndor such as verisign can step in and say that the public key being provided is indeed right..

ALL OS's trust a handful of certification authorities and smaller certificate issuers need to be certified by one of the large certifiers making a chain of certifiers if you get what I mean...

Anyways coming back to the point.. I had a similiar problem when programming a java applet and a java server ( Hopefully some day I will write a complete blogpost about how I got all the security to work :) )

In essence what I had to do was to extract the public keys from the server and store it in a keystore inside my applet and when I connected to the server I used this key store to create a trust factory and that trust factory to create the ssl connection. There are alterante procedures as well such as adding the key to the JVM's trusted host and modifying the default trust store on start up..

I did this around two months back and dont have source code on me right now.. use google and you should be able to solve this problem. If you cant message me back and I can provide you the relevent source code for the project .. Dont know if this solves your problem since you havent provided the code which causes these exceptions. Furthermore I was working wiht applets thought I cant see why it wont work on Serverlets...

P.S I cant get source code before the weekend since external SSH is disabled in my office :(

回梦 2024-11-26 16:51:20

SSLHandshakeException 可以通过两种方式解决。

  1. 合并 SSL
  • 获取 SSL(通过询问源系统管理员,也可以
    通过 openssl 命令下载,或者从任何可以下载证书的浏览器)

  • 将证书添加到位于以下位置的信任存储 (cacerts)
    jre/lib/security

  • 在虚拟机参数中提供信任库位置:

-Djavax.net.ssl.trustStore=/path/to/file

  1. 忽略 SSL

    对于这个 #2,请访问我在另一个 StackOverflow 网站上的其他答案:
    如何忽略 SSL 验证使用 Java 忽略 SSL 证书错误

SSLHandshakeException can be resolved in 2 ways.

  1. Incorporating SSL
  • Get the SSL (by asking the source system administrator, can also
    be downloaded by the openssl command, or from any browser you can download the certificate)

  • Add the certificate to the trust store (cacerts) located at
    jre/lib/security

  • provide the truststore location in VM arguments as:

-Djavax.net.ssl.trustStore=/path/to/file

  1. Ignoring SSL

    For this #2, please visit my other answer on another StackOverflow website:
    How to ignore SSL verification Ignore SSL Certificate Errors with Java

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文