130

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

我有: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 连接?(可能没有 KeyManager 和 Trust manager 等。)

4

18 回答 18

163

https://mms.nw.ru使用不在默认信任管理器集中的自签名证书。要解决此问题,请执行以下操作之一:

  • 使用接受任何证书SSLContext的 a进行配置(见下文)。TrustManager
  • 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;
        }
    }
}
于 2009-12-01T20:52:31.233 回答
47

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 的博客No more 'unable to find valid authentication path to requested target'

于 2009-12-01T20:52:01.783 回答
23

除了 Pascal Thivent 的正确答案,另一种方法是从 Firefox 中保存证书(查看证书 -> 详细信息 -> 导出)或openssl s_client将其导入到信任库中。

只有当您有办法验证该证书时,您才应该这样做。如果做不到这一点,请在第一次连接时进行,如果证书在后续连接中意外更改,它至少会给您一个错误。

要将其导入信任存储,请使用:

keytool -importcert -keystore truststore.jks -file servercert.pem

默认情况下,默认的信任库应该是$JAVA_HOME/jre/lib/security/cacerts,它的密码应该是changeit,请参阅JSSE 参考指南了解详细信息。

如果您不想全局允许该证书,但只允许这些连接,则可以为它创建一个SSLContext

TrustManagerFactory tmf = TrustManagerFactory
    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream fis = new FileInputStream("/.../truststore.jks");
ks.load(fis, null);
// or ks.load(fis, "thepassword".toCharArray());
fis.close();

tmf.init(ks);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);

然后,您需要为 Apache HTTP Client 3.x 设置它,方法是实现一个如果它SecureProtocolSocketFactory使用 this SSLContext(这里有例子)。

Apache HTTP Client 4.x(除了最早的版本)直接支持传递SSLContext.

于 2012-05-02T00:31:48.850 回答
14

Apache HttpClient 4.5 方式:

org.apache.http.ssl.SSLContextBuilder sslContextBuilder = SSLContextBuilder.create();
sslContextBuilder.loadTrustMaterial(new org.apache.http.conn.ssl.TrustSelfSignedStrategy());
SSLContext sslContext = sslContextBuilder.build();
org.apache.http.conn.ssl.SSLConnectionSocketFactory sslSocketFactory =
        new SSLConnectionSocketFactory(sslContext, new org.apache.http.conn.ssl.DefaultHostnameVerifier());

HttpClientBuilder httpClientBuilder = HttpClients.custom().setSSLSocketFactory(sslSocketFactory);
httpClient = httpClientBuilder.build();

注意:org.apache.http.conn.ssl.SSLContextBuilder弃用并且org.apache.http.ssl.SSLContextBuilder是新的(注意conn后者的包名称中缺少通知)。

于 2015-08-07T09:11:47.333 回答
14

对于 Apache HttpClient 4.5+ & Java8:

SSLContext sslContext = SSLContexts.custom()
        .loadTrustMaterial((chain, authType) -> true).build();

SSLConnectionSocketFactory sslConnectionSocketFactory =
        new SSLConnectionSocketFactory(sslContext, new String[]
        {"SSLv2Hello", "SSLv3", "TLSv1","TLSv1.1", "TLSv1.2" }, null,
        NoopHostnameVerifier.INSTANCE);
CloseableHttpClient client = HttpClients.custom()
        .setSSLSocketFactory(sslConnectionSocketFactory)
        .build();

但是,如果您的 HttpClient 使用 ConnectionManager 来寻求连接,例如这样:

 PoolingHttpClientConnectionManager connectionManager = new 
         PoolingHttpClientConnectionManager();

 CloseableHttpClient client = HttpClients.custom()
            .setConnectionManager(connectionManager)
            .build();

HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory)没有效果,问题没有解决。

因为HttpClient使用指定的connectionManager寻求连接,而指定的connectionManager没有注册我们自定义的SSLConnectionSocketFactory。要解决这个问题,应该在 connectionManager 中注册自定义的 SSLConnectionSocketFactory。正确的代码应该是这样的:

PoolingHttpClientConnectionManager connectionManager = new 
    PoolingHttpClientConnectionManager(RegistryBuilder.
                <ConnectionSocketFactory>create()
      .register("http",PlainConnectionSocketFactory.getSocketFactory())
      .register("https", sslConnectionSocketFactory).build());

CloseableHttpClient client = HttpClients.custom()
            .setConnectionManager(connectionManager)
            .build();
于 2017-08-17T11:32:50.287 回答
10

http://hc.apache.org/httpclient-3.x/sslguide.html

Protocol.registerProtocol("https", 
new Protocol("https", new MySSLSocketFactory(), 443));
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("https://www.whatever.com/");
try {
  httpclient.executeMethod(httpget);
      System.out.println(httpget.getStatusLine());
} finally {
      httpget.releaseConnection();
}

可以在此处找到 MySSLSocketFactory 示例。它引用 a TrustManager,您可以对其进行修改以信任所有内容(尽管您必须考虑这一点!)

于 2009-12-01T20:53:35.180 回答
8

想在这里粘贴答案:

在 Apache HttpClient 4.5.5

如何使用 Apache 客户端 4.5.5 处理无效的 SSL 证书?

HttpClient httpClient = HttpClients
            .custom()
            .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, TrustAllStrategy.INSTANCE).build())
            .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
            .build();
于 2019-02-15T09:29:09.643 回答
6

一旦你有了一个 Java Cert Store(通过使用上面创建的伟大的InstallCert 类),你可以通过在 java 启动时传递“javax.net.ssl.trustStore”参数来让 java 使用它。

前任:

java -Djavax.net.ssl.trustStore=/path/to/jssecacerts MyClassName
于 2009-12-01T21:52:39.920 回答
3

自签名测试证书可能会遇到的另一个问题是:

java.io.IOException:HTTPS 主机名错误:应该是...

当您尝试访问 HTTPS url 时会发生此错误。您可能已经将服务器证书安装到 JRE 的密钥库中。但是这个错误意味着服务器证书的名称与 URL 中提到的服务器的实际域名不匹配。当您使用非 CA 颁发的证书时,通常会发生这种情况。

此示例显示如何编写忽略证书服务器名称的 HttpsURLConnection DefaultHostnameVerifier:

http://www.java-samples.com/showtutorial.php?tutorialid=211

于 2011-08-25T05:29:00.047 回答
3

EasySSLProtocolSocketFactory 给我带来了问题,所以我最终实现了自己的 ProtocolSocketFactory。

首先你需要注册它:

Protocol.registerProtocol("https", new Protocol("https", new TrustAllSSLSocketFactory(), 443));

HttpClient client = new HttpClient();
...

然后实现ProtocolSocketFactory:

class TrustAllSSLSocketFactory implements ProtocolSocketFactory {

    public static final TrustManager[] TRUST_ALL_CERTS = new TrustManager[]{
        new X509TrustManager() {
            public void checkClientTrusted(final X509Certificate[] certs, final String authType) {

            }

            public void checkServerTrusted(final X509Certificate[] certs, final String authType) {

            }

            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        }
    };

    private TrustManager[] getTrustManager() {
        return TRUST_ALL_CERTS;
    }

    public Socket createSocket(final String host, final int port, final InetAddress clientHost,
                               final int clientPort) throws IOException {
        return getSocketFactory().createSocket(host, port, clientHost, clientPort);
    }

    @Override
    public Socket createSocket(final String host, final int port, final InetAddress localAddress,
                               final int localPort, final HttpConnectionParams params) throws IOException {
        return createSocket(host, port);
    }

    public Socket createSocket(final String host, final int port) throws IOException {
        return getSocketFactory().createSocket(host, port);
    }

    private SocketFactory getSocketFactory() throws UnknownHostException {
        TrustManager[] trustAllCerts = getTrustManager();

        try {
            SSLContext context = SSLContext.getInstance("SSL");
            context.init(null, trustAllCerts, new SecureRandom());

            final SSLSocketFactory socketFactory = context.getSocketFactory();
            HttpsURLConnection.setDefaultSSLSocketFactory(socketFactory);
            return socketFactory;
        } catch (NoSuchAlgorithmException | KeyManagementException exception) {
            throw new UnknownHostException(exception.getMessage());
        }
    }
}

注意:这是 HttpClient 3.1 和 Java 8

于 2017-05-08T17:24:05.800 回答
2

要在运行时轻松添加您信任的主机而无需放弃所有检查,请尝试此处的代码:http ://code.google.com/p/self-signed-cert-trust-manager/ 。

于 2012-01-30T16:48:23.737 回答
1

我碰巧遇到了同样的问题,突然间我所有的进口商品都不见了。我尝试删除 .m2 文件夹中的所有内容。并尝试重新导入所有内容,但仍然没有任何效果。最后,我打开了 IDE 抱怨无法在我的浏览器中下载的网站。并看到了它正在使用的证书,并在我的

$ keytool -v -list  PATH_TO_JAVA_KEYSTORE

我的密钥库的路径是 /Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/security/cacerts

该特定证书不存在。

因此,您所要做的就是再次将证书放入 JAVA JVM 密钥库中。可以使用以下命令完成。

$ keytool -import -alias ANY_NAME_YOU_WANT_TO_GIVE -file PATH_TO_YOUR_CERTIFICATE -keystore PATH_OF_JAVA_KEYSTORE

如果它要求输入密码,请尝试默认密码 'changeit' 如果在运行上述命令时出现权限错误。在 Windows 中以管理模式打开它。在 mac 和 unix 中使用 sudo。

成功添加密钥后,您可以使用以下命令查看它:

$ keytool -v -list  /Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/security/cacerts 

您可以使用 teh 命令仅查看 SHA-1

$ keytool -list  /Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/security/cacerts 
于 2019-03-20T11:32:56.433 回答
0

链接逐步解释了您的要求。如果您并不真正关心哪个证书,您可以继续以下链接中的流程。

注意您可能需要仔细检查您在做什么,因为这是不安全的操作。

于 2012-03-05T10:50:07.683 回答
0

使用InstallCert来生成jssecacerts文件并且 -Djavax.net.ssl.trustStore=/path/to/jssecacerts效果很好。

于 2012-01-28T00:53:31.053 回答
0

按照下面针对 Java 1.7 给出的说明,使用 InstallCert.java 程序文件创建 SSL 证书。

https://github.com/escline/InstallCert

你必须重新启动tomcat

于 2018-12-18T17:36:34.510 回答
0

将以下内容与 DefaultTrustManager 一起使用,它像魅力一样在 httpclient 中工作。万分感谢!!@Kevin 和其他所有贡献者

    SSLContext ctx = null;
    SSLConnectionSocketFactory sslsf = null;
    try {

        ctx = SSLContext.getInstance("TLS");
        ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
        SSLContext.setDefault(ctx);

        sslsf = new SSLConnectionSocketFactory(
                ctx,
                new String[] { "TLSv1" },
                null,
                SSLConnectionSocketFactory.getDefaultHostnameVerifier());

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

     CloseableHttpClient client = HttpClients.custom()
            .setSSLSocketFactory(sslsf)
            .build();
于 2019-01-19T07:02:17.713 回答
0

我正在使用 httpclient 3.1.X ,这对我有用

        try {
        SSLContext sslContext = SSLContext.getInstance("TLS");
        TrustManager trustManager = new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        sslContext.init(null, new TrustManager[]{trustManager}, null);
        SslContextSecureProtocolSocketFactory socketFactory = new SslContextSecureProtocolSocketFactory(sslContext,false);
        Protocol.registerProtocol("https", new Protocol("https", (ProtocolSocketFactory) socketFactory, 443));//同样会影响到HttpUtils
    } catch (Throwable e) {
        e.printStackTrace();

}

public class SslContextSecureProtocolSocketFactory implements      SecureProtocolSocketFactory {

private SSLContext sslContext;
private boolean verifyHostname;

public SslContextSecureProtocolSocketFactory(SSLContext sslContext, boolean verifyHostname) {
    this.verifyHostname = true;
    this.sslContext = sslContext;
    this.verifyHostname = verifyHostname;
}

public SslContextSecureProtocolSocketFactory(SSLContext sslContext) {
    this(sslContext, true);
}

public SslContextSecureProtocolSocketFactory(boolean verifyHostname) {
    this((SSLContext)null, verifyHostname);
}

public SslContextSecureProtocolSocketFactory() {
    this((SSLContext)null, true);
}

public synchronized void setHostnameVerification(boolean verifyHostname) {
    this.verifyHostname = verifyHostname;
}

public synchronized boolean getHostnameVerification() {
    return this.verifyHostname;
}

public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException, UnknownHostException {
    SSLSocketFactory sf = this.getSslSocketFactory();
    SSLSocket sslSocket = (SSLSocket)sf.createSocket(host, port, clientHost, clientPort);
    this.verifyHostname(sslSocket);
    return sslSocket;
}

public Socket createSocket(String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params) throws IOException, UnknownHostException, ConnectTimeoutException {
    if(params == null) {
        throw new IllegalArgumentException("Parameters may not be null");
    } else {
        int timeout = params.getConnectionTimeout();
        Socket socket = null;
        SSLSocketFactory socketfactory = this.getSslSocketFactory();
        if(timeout == 0) {
            socket = socketfactory.createSocket(host, port, localAddress, localPort);
        } else {
            socket = socketfactory.createSocket();
            InetSocketAddress localaddr = new InetSocketAddress(localAddress, localPort);
            InetSocketAddress remoteaddr = new InetSocketAddress(host, port);
            socket.bind(localaddr);
            socket.connect(remoteaddr, timeout);
        }

        this.verifyHostname((SSLSocket)socket);
        return socket;
    }
}

public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
    SSLSocketFactory sf = this.getSslSocketFactory();
    SSLSocket sslSocket = (SSLSocket)sf.createSocket(host, port);
    this.verifyHostname(sslSocket);
    return sslSocket;
}

public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
    SSLSocketFactory sf = this.getSslSocketFactory();
    SSLSocket sslSocket = (SSLSocket)sf.createSocket(socket, host, port, autoClose);
    this.verifyHostname(sslSocket);
    return sslSocket;
}

private void verifyHostname(SSLSocket socket) throws SSLPeerUnverifiedException, UnknownHostException {
    synchronized(this) {
        if(!this.verifyHostname) {
            return;
        }
    }

    SSLSession session = socket.getSession();
    String hostname = session.getPeerHost();

    try {
        InetAddress.getByName(hostname);
    } catch (UnknownHostException var10) {
        throw new UnknownHostException("Could not resolve SSL sessions server hostname: " + hostname);
    }

    X509Certificate[] certs = (X509Certificate[])((X509Certificate[])session.getPeerCertificates());
    if(certs != null && certs.length != 0) {
        X500Principal subjectDN = certs[0].getSubjectX500Principal();
        List cns = this.getCNs(subjectDN);
        boolean foundHostName = false;
        Iterator i$ = cns.iterator();
        AntPathMatcher matcher  = new AntPathMatcher();
        while(i$.hasNext()) {
            String cn = (String)i$.next();
            if(matcher.match(cn.toLowerCase(),hostname.toLowerCase())) {
                foundHostName = true;
                break;
            }
        }

        if(!foundHostName) {
            throw new SSLPeerUnverifiedException("HTTPS hostname invalid: expected \'" + hostname + "\', received \'" + cns + "\'");
        }
    } else {
        throw new SSLPeerUnverifiedException("No server certificates found!");
    }
}

private List<String> getCNs(X500Principal subjectDN) {
    ArrayList cns = new ArrayList();
    StringTokenizer st = new StringTokenizer(subjectDN.getName(), ",");

    while(st.hasMoreTokens()) {
        String cnField = st.nextToken();
        if(cnField.startsWith("CN=")) {
            cns.add(cnField.substring(3));
        }
    }

    return cns;
}

protected SSLSocketFactory getSslSocketFactory() {
    SSLSocketFactory sslSocketFactory = null;
    synchronized(this) {
        if(this.sslContext != null) {
            sslSocketFactory = this.sslContext.getSocketFactory();
        }
    }

    if(sslSocketFactory == null) {
        sslSocketFactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
    }

    return sslSocketFactory;
}

public synchronized void setSSLContext(SSLContext sslContext) {
    this.sslContext = sslContext;
}

}

于 2016-10-14T06:32:01.397 回答
0

对于 HttpClient,我们可以这样做:

SSLContext ctx = SSLContext.getInstance("TLS");
        ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
        SSLContext.setDefault(ctx);

        String uri = new StringBuilder("url").toString();

        HostnameVerifier hostnameVerifier = new HostnameVerifier() {
            @Override
            public boolean verify(String arg0, SSLSession arg1) {
                return true;
            }
        };

        HttpClient client = HttpClientBuilder.create().setSSLContext(ctx)
                .setSSLHostnameVerifier(hostnameVerifier).build()
于 2018-05-23T15:18:10.580 回答