10

我正在尝试调用 REST API,但出现以下异常(最后是 Complete StackTrace):

"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"

我向 API 提供者询问了这个问题,并说您使用的 SSL 库有问题。

你将如何解决这个问题?使用相同的代码(如下),我确实毫无问题地调用了 NIMBLE API REST,但在这种情况下它不起作用。然后,我没有任何文件证书(.cer)。

我需要停用 SSL 验证,因为安全方法是我已经拥有的 API KEY。

有什么建议么?

非常感谢!

==== 控制台:====

POST https://api.nexalogy.com/project/create?api_key=XXXXXXXXXXXXXXXXXXXX
HTTP Header:"Content-Type" "application/json"
HTTP Body:[{"name":"project1","lang":"en","type":"twitter"}]
api_key:XXXXXXXXXXXXXXXXXXXX
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

我也尝试了以下形式,例外是相同的:

POST https://api.nexalogy.com/project/create
HTTP Header:"Content-Type" "application/json"
HTTP Header:"api_key" "XXXXXXXXXXXXXXXXXXXX"
HTTP Body:[{"name":"project1","lang":"en","type":"twitter"}]
api_key:XXXXXXXXXXXXXXXXXXXX
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

==== 代码:====

package servlet;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/AddProject")
public class AddProject extends HttpServlet {
    private static final long serialVersionUID = 1L;
    public AddProject() {
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String body="[{\"name\":\"project1\",\"lang\":\"en\",\"type\":\"twitter\"}]";
        String api_key="XXXXXXXXXXXXXXXXXXXX";
        String str_response="";
        String line="";
        URL url = new URL("https://api.nexalogy.com/project/create?api_key="+api_key);
        try{
            HttpURLConnection connection = (HttpURLConnection)url.openConnection();
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type","application/json");
            System.out.println("POST https://api.nexalogy.com/project/create?api_key="+api_key);
            System.out.println("HTTP Header:"+"\"Content-Type\" \"application/json\"");
            System.out.println("HTTP Body:"+body);
            System.out.println("api_key:"+api_key);
            connection.setUseCaches(false);
            connection.setDoInput(true);
            connection.setDoOutput(true);
            DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
            wr.writeBytes(body);
            wr.flush();
            wr.close();
            InputStream is = connection.getInputStream();
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader rd = new BufferedReader(isr);
            while ((line = rd.readLine()) != null) str_response+= line + '\r';
            rd.close();
            System.out.println("str_response:"+str_response);
        }catch(Exception e){
            e.printStackTrace(System.out);
            //throw new RuntimeException(e);
        }
    }
}

==== 完成 StackTrace:====

com.sun.jersey.api.client.ClientHandlerException: 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
    at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:131)
    at com.sun.jersey.api.client.Client.handle(Client.java:616)
    at com.sun.jersey.api.client.WebResource.handle(WebResource.java:559)
    at com.sun.jersey.api.client.WebResource.post(WebResource.java:230)
    at engine_brandchats.twitter_api_create_project_0_1.Twitter_api_create_project.tREST_2Process(Twitter_api_create_project.java:955)
    at engine_brandchats.twitter_api_create_project_0_1.Twitter_api_create_project.tJava_1Process(Twitter_api_create_project.java:635)
    at engine_brandchats.twitter_api_create_project_0_1.Twitter_api_create_project.runJobInTOS(Twitter_api_create_project.java:1641)
    at engine_brandchats.twitter_api_create_project_0_1.Twitter_api_create_project.main(Twitter_api_create_project.java:1494)
Caused by: 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
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Unknown Source)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(Unknown Source)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(Unknown Source)
    at com.sun.jersey.client.urlconnection.URLConnectionClientHandler$1$1.getOutputStream(URLConnectionClientHandler.java:203)
    at com.sun.jersey.api.client.CommittingOutputStream.commitWrite(CommittingOutputStream.java:117)
    at com.sun.jersey.api.client.CommittingOutputStream.write(CommittingOutputStream.java:89)
    at sun.nio.cs.StreamEncoder.writeBytes(Unknown Source)
    at sun.nio.cs.StreamEncoder.implFlushBuffer(Unknown Source)
    at sun.nio.cs.StreamEncoder.implFlush(Unknown Source)
    at sun.nio.cs.StreamEncoder.flush(Unknown Source)
    at java.io.OutputStreamWriter.flush(Unknown Source)
    at java.io.BufferedWriter.flush(Unknown Source)
    at com.sun.jersey.core.util.ReaderWriter.writeToAsString(ReaderWriter.java:191)
    at com.sun.jersey.core.provider.AbstractMessageReaderWriterProvider.writeToAsString(AbstractMessageReaderWriterProvider.java:128)
    at com.sun.jersey.core.impl.provider.entity.StringProvider.writeTo(StringProvider.java:88)
    at com.sun.jersey.core.impl.provider.entity.StringProvider.writeTo(StringProvider.java:58)
    at com.sun.jersey.api.client.TerminatingClientHandler.writeRequestEntity(TerminatingClientHandler.java:305)
    at com.sun.jersey.client.urlconnection.URLConnectionClientHandler._invoke(URLConnectionClientHandler.java:182)
    at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:129)
    ... 7 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.validator.PKIXValidator.doBuild(Unknown Source)
    at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
    at sun.security.validator.Validator.validate(Unknown Source)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(Unknown Source)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
    ... 35 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
    at java.security.cert.CertPathBuilder.build(Unknown Source)
    ... 41 more

已编辑 2013-06-13 解决方案:实现 X509TrustManager

添加以下代码...

HttpsURLConnection connection = (HttpsURLConnection)url.openConnection();
connection.setRequestMethod("POST");
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
if (connection instanceof HttpsURLConnection) {
    try {
        KeyManager[] km = null;
        TrustManager[] tm = {new RelaxedX509TrustManager()};
        SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, tm, new java.security.SecureRandom());
        SSLSocketFactory sf = sslContext.getSocketFactory();
        ((HttpsURLConnection)connection).setSSLSocketFactory(sf);
        System.out.println("setSSLSocketFactory OK!");
    }catch (java.security.GeneralSecurityException e) {
        System.out.println("GeneralSecurityException: "+e.getMessage());
    }
}

...并添加以下类(实现 X509TrustManager)

class RelaxedX509TrustManager implements X509TrustManager {
    public boolean isClientTrusted(java.security.cert.X509Certificate[] chain){ return true; }
    public boolean isServerTrusted(java.security.cert.X509Certificate[] chain){ return true; }
    public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; }
    public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String input) {}
    public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String input) {}
}
4

3 回答 3

11

尝试这个

public void disableCertificates() {
    TrustManager[] trustAllCerts = new TrustManager[]{
        new X509TrustManager() {

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }

            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] certs, String authType) {
            }

            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] certs, String authType) {
            }
        }
    };

    // Install the all-trusting trust manager
    try {
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    } catch (Exception e) {
    }
}
于 2013-06-12T13:24:17.487 回答
3

我需要停用 SSL 验证,因为安全方法是我已经拥有的 API KEY。

目前尚不清楚您认为 API 密钥(及其提供的安全方面)与 SSL/TLS 提供的安全性有何关系:它们当然没有解决相同的安全方面。SSL/TLS 是关于保护数据传输不被窃听和篡改。

如果您针对此 SSL 测试服务检查您尝试联系的服务器,您会发现该服务器需要一个支持服务器名称指示 (SNI) 的客户端:这允许服务器托管具有不同证书的多个主机。

如果您的客户端不支持 SNI(Java 仅在客户端从版本 7 开始支持它),请求将显示与缩进的证书不同的证书:它可能无法通过证书验证或主机名验证程序。禁用任一检查会使连接容易受到中间人攻击。

  • 我想说您遇到问题的最可能原因是您使用的 Java 版本不支持 SNI(例如 Java 6)。

  • 您使用的 JRE 也可能在其默认信任存储中没有此特定 CA。您可以尝试从其他来源(例如 Mozilla 捆绑包,通常与 cURL 一起推荐)获取您愿意信任的 CA 证书的转换列表。您可能首先需要了解 CA 证书是什么。

    正如JSSE 参考指南所说

    重要说明:JDK 在 /lib/security/cacerts 文件中附带了数量有限的受信任根证书。如 keytool 中所述,如果您将此文件用作信任库,则您有责任维护(即添加/删除)此文件中包含的证书。

    根据您联系的服务器的证书配置,您可能需要添加额外的根证书。从适当的供应商处获取所需的特定根证书。

无论哪种方式:停用 SSL 验证都不能解决您的问题。

编辑:

您尝试使用的服务似乎具有由 StartSSL 颁发的证书,这显然不是默认与 Oracle JRE 捆绑的 CA 之一。

您需要从 StartSSL 下载它(或从您已经拥有的受信任捆绑包中导出它,它称为“StartCom ...”)并使用 keytool 将其导入您的cacerts商店(或者如果您使用的是其他信任商店,则使用不同的一):

keytool -import -keystore /path/to/jre/lib/security/cacerts -alias startssl -file startssl.crt

(当然,根据需要调整startssl证书文件的路径和名称。)

于 2013-06-12T14:10:31.187 回答
-2

请使用具有完整证书链的证书。这意味着至少需要根证书。

您只导入了对方的最终证书,实现无法验证证书链。至少需要根证书。

于 2013-06-12T13:49:50.193 回答