如何使用ApacheHttpClient处理无效的SSL证书?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (607)

我知道,关于这个问题有很多不同的问题和很多答案......但我无法理解......

我有:ubuntu-9.10-desktop-amd64 + NetBeans6.7.1从“关闭”安装。代表。我需要通过HTTPS连接到某个站点。为此,我使用Apache的HttpClient。

从教程:

“一旦你正确安装了JSSE,通过SSL进行安全的HTTP通信应该 与普通的HTTP通信一样简单。” 还有一些例子:

HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("https://www.verisign.com/"); 
try { 
  httpclient.executeMethod(httpget);
  System.out.println(httpget.getStatusLine());
} finally {
  httpget.releaseConnection();
}

现在,我写到:

HttpClient client = new HttpClient();

HttpMethod get = new GetMethod("https://mms.nw.ru");
//get.setDoAuthentication(true);

try {
    int status = client.executeMethod(get);
    System.out.println(status);

    BufferedInputStream is = new BufferedInputStream(get.getResponseBodyAsStream());
    int r=0;byte[] buf = new byte[10];
    while((r = is.read(buf)) > 0) {
        System.out.write(buf,0,r);
    }

} catch(Exception ex) {
    ex.printStackTrace();
}

因此,我有一组错误:

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 sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
        at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1627)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:204)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:198)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:994)
        at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:142)
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:533)
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:471)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:904)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1132)
        at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:643)
        at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:78)
        at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
        at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
        at org.apache.commons.httpclient.HttpConnection.flushRequestOutputStream(HttpConnection.java:828)
        at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2116)
        at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096)
        at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)
        at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
        at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
        at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
        at simpleapachehttp.Main.main(Main.java:41)
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(PKIXValidator.java:302)
        at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:205)
        at sun.security.validator.Validator.validate(Validator.java:235)
        at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:147)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:230)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:270)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:973)
        ... 17 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:191)
        at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:255)
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:297)
        ... 23 more

要创建最简单的SSL连接,我要做什么?(可能没有密钥管理器和信任管理器等。)

提问于
用户回答回答于

https://mms.nw.ru使用自签名证书,这显然不包含在默认的信任管理器集合中。

需要以下其中一项:

  • 使用接受任何证书的TrustManager配置SSLContext(请参见下文)
  • 使用包含您的证书的适当信任存储配置SSLContext
  • 将该站点的证书添加到默认的Java信任库。

下面是一个示例程序,它创建了一个接受任何证书的(主要是无价值的)SSL上下文:

import java.net.URL;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class SSLTest {

    public static void main(String [] args) throws Exception {
        // configure the SSLContext with a TrustManager
        SSLContext ctx = SSLContext.getInstance("TLS");
        ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
        SSLContext.setDefault(ctx);

        URL url = new URL("https://mms.nw.ru");
        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
        conn.setHostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String arg0, SSLSession arg1) {
                return true;
            }
        });
        System.out.println(conn.getResponseCode());
        conn.disconnect();
    }

    private static class DefaultTrustManager implements X509TrustManager {

        @Override
        public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}

        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    }
}
用户回答回答于

https://mms.nw.ru可能使用不是由证书颁发机构颁发的证书。因此,您需要将证书添加到您信任的Java密钥存储中,如无法找到请求目标的有效证书路径所述

在与https协议中运行的启用了SSL的服务器一起工作的客户端上工作时,如果服务器证书不是由证书颁发机构颁发的,而是由自签名的或由其发布的,则可能会出现错误“无法找到所请求目标的有效证书路径”一个私人CMS。 不要惊慌。如果您的客户端是用Java编写的,您只需将服务器证书添加到可信的Java密钥存储区。您可能想知道如何无法访问安装服务器的计算机。有一个简单的程序可以帮助你。请下载Java程序并运行 % java InstallCert _web_site_hostname_ 该程序打开了与指定主机的连接并启动了SSL握手。它打印出现错误的异常堆栈跟踪并显示服务器使用的证书。现在它会提示您将证书添加到您的可信KeyStore中。 如果您改变了主意,请输入'q'。如果您确实想要添加证书,请输入“1”或其他数字以添加其他证书,即使是CA证书,但您通常不希望这样做。一旦你做出选择,程序将显示完整的证书,然后将其添加到当前目录中名为'jssecacerts'的Java KeyStore中。 要在程序中使用它,可以将JSSE配置为其信任存储或将其复制到$ JAVA_HOME / jre / lib / security目录中。如果希望所有Java应用程序都将该证书识别为可信,而不仅仅是JSSE,则还可以覆盖该目录中的cacerts文件。 毕竟,JSSE将能够与主机完成握手,可以通过再次运行程序来验证。 要了解更多详情,你可以查看Leeland的博客没有更多'无法找到有效的认证路径到要求的目标'

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励