我如何停用SSL验证?

时间:2013-06-12 13:06:09

标签: java api rest ssl

我正在尝试调用REST API,但是我得到以下异常(最后完成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) {}
}

3 个答案:

答案 0 :(得分:8)

试试这个

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) {
    }
}

答案 1 :(得分:3)

  

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

目前尚不清楚您认为API密钥(以及它提供的安全方面)与SSL / TLS提供的安全性有何关系:它们肯定无法解决相同的安全问题。 SSL / TLS是关于保护数据传输免受窃听和更改。

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

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

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

  • 您正在使用的JRE也可能在其默认信任库中没有此特定CA.您可以尝试从其他来源(例如,经常推荐使用cURL的Mozilla捆绑包)转换您愿意信任的CA证书列表。您可能需要先了解CA证书的内容。

    作为JSSE reference guide says

      

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

         

    根据您联系的服务器的证书配置,   您可能需要添加其他根证书。获得所需   来自相应供应商的特定根证书。

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

修改

看起来您尝试使用的服务具有由StartSSL颁发的证书,该证书显然不是Oracle JRE默认捆绑的CA之一。

您需要download it from StartSSL(或者从您已拥有的受信任的捆绑包中导出它,它被称为“StartCom ...”)并使用keytool(或其他)将其导入您的cacerts商店信任商店,如果你使用另一个):

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

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

答案 2 :(得分:-2)

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

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