39

使用HttpClient,我在尝试通过 HTTPS 通信时收到以下错误:

线程“主”javax.net.ssl.SSLPeerUnverifiedException 中的异常:对等体未通过身份验证。

这是我的代码:

URI loginUri = new URI("https://myUrl.asp");

HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet( loginUri );
HttpResponse response = httpclient.execute( httpget );

如何抑制或消除此错误?

4

6 回答 6

17

注意:不要在生产代码中执行此操作,请改用 http 或上面建议的实际自签名公钥。

在 HttpClient 4.xx 上:

import static org.junit.Assert.assertEquals;

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.junit.Test;

public class HttpClientTrustingAllCertsTest {

    @Test
    public void shouldAcceptUnsafeCerts() throws Exception {
        DefaultHttpClient httpclient = httpClientTrustingAllSSLCerts();
        HttpGet httpGet = new HttpGet("https://host_with_self_signed_cert");
        HttpResponse response = httpclient.execute( httpGet );
        assertEquals("HTTP/1.1 200 OK", response.getStatusLine().toString());
    }

    private DefaultHttpClient httpClientTrustingAllSSLCerts() throws NoSuchAlgorithmException, KeyManagementException {
        DefaultHttpClient httpclient = new DefaultHttpClient();

        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, getTrustingManager(), new java.security.SecureRandom());

        SSLSocketFactory socketFactory = new SSLSocketFactory(sc);
        Scheme sch = new Scheme("https", 443, socketFactory);
        httpclient.getConnectionManager().getSchemeRegistry().register(sch);
        return httpclient;
    }

    private TrustManager[] getTrustingManager() {
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }

            @Override
            public void checkClientTrusted(X509Certificate[] certs, String authType) {
                // Do nothing
            }

            @Override
            public void checkServerTrusted(X509Certificate[] certs, String authType) {
                // Do nothing
            }

        } };
        return trustAllCerts;
    }
}
于 2012-10-04T18:21:11.237 回答
17

这个答案遵循owlsteadMat的回应。它适用于 SE/EE 安装,不适用于 ME/mobile/Android SSL。

由于尚未有人提及它,我将提及解决此问题的“生产方式”:按照HttpClient 中的 AuthSSLProtocolSocketFactory 类中的步骤更新您的信任库和密钥库。

  1. 导入可信证书并生成信任库文件

keytool -import -alias "my server cert" -file server.crt -keystore my.truststore

  1. 生成新密钥(使用与信任库相同的密码)

keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore

  1. 发出证书签名请求 (CSR)

keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore

  1. (自签名或让您的证书签名)

  2. 导入可信 CA 根证书

keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore

  1. 导入包含完整证书链的 PKCS#7 文件

keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore

  1. 验证生成的密钥库文件的内容

keytool -list -v -keystore my.keystore

如果您没有服务器证书,请生成 JKS 格式的证书,然后将其导出为 CRT 文件。来源:keytool 文档

keytool -genkey -alias server-alias -keyalg RSA -keypass changeit
    -storepass changeit -keystore my.keystore

keytool -export -alias server-alias -storepass changeit
    -file server.crt -keystore my.keystore
于 2013-03-11T22:35:11.947 回答
12

使用 HttpClient 3.x,您需要这样做:

Protocol easyHttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
Protocol.registerProtocol("https", easyHttps);

可以在此处找到 EasySSLProtocolSocketFactory 的实现。

于 2010-02-22T20:34:40.613 回答
4

如果您的服务器基于 JDK 7 并且您的客户端在 JDK 6 上并使用 SSL 证书,则会出现此异常。在 JDK 7 中,默认情况下禁用 sslv2hello 消息握手,而在 JDK 6 中启用 sslv2hello 消息握手。因此,当您的客户端尝试连接服务器时,将向服务器发送一条 sslv2hello 消息,并且由于 sslv2hello 消息禁用,您将收到此异常。要解决此问题,您必须将客户端移至 JDK 7,或者必须使用 JDK 的 6u91 版本。但要获得此版本的 JDK,您必须获得

于 2015-08-26T07:44:43.880 回答
0

返回“secureClient”的方法(在 Java 7 环境中 - NetBeans IDE 和 GlassFish Server:端口 https 默认为 3920 ),希望这会有所帮助:

public DefaultHttpClient secureClient() {
    DefaultHttpClient httpclient = new DefaultHttpClient();
    SSLSocketFactory sf;

    KeyStore trustStore;
    FileInputStream trustStream = null;
    File truststoreFile;
    // java.security.cert.PKIXParameters for the trustStore
    PKIXParameters pkixParamsTrust;

    KeyStore keyStore;
    FileInputStream keyStream = null;
    File keystoreFile;
    // java.security.cert.PKIXParameters for the keyStore
    PKIXParameters pkixParamsKey;

    try {
        trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        truststoreFile = new File(TRUSTSTORE_FILE);
        keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keystoreFile = new File(KEYSTORE_FILE);
        try {
            trustStream = new FileInputStream(truststoreFile);
            keyStream = new FileInputStream(keystoreFile);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            trustStore.load(trustStream, PASSWORD.toCharArray());
            keyStore.load(keyStream, PASSWORD.toCharArray());
        } catch (IOException ex) {
            Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
        } catch (CertificateException ex) {
            Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            pkixParamsTrust = new PKIXParameters(trustStore);
            // accepts Server certificate generated with keytool and (auto) signed by SUN
            pkixParamsTrust.setPolicyQualifiersRejected(false);
        } catch (InvalidAlgorithmParameterException ex) {
            Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            pkixParamsKey = new PKIXParameters(keyStore);
            // accepts Client certificate generated with keytool and (auto) signed by SUN
            pkixParamsKey.setPolicyQualifiersRejected(false);
        } catch (InvalidAlgorithmParameterException ex) {
            Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            sf = new SSLSocketFactory(trustStore);
            ClientConnectionManager manager = httpclient.getConnectionManager();
            manager.getSchemeRegistry().register(new Scheme("https", 3920, sf));
        } catch (KeyManagementException ex) {
            Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnrecoverableKeyException ex) {
            Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
        }

    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
    } catch (KeyStoreException ex) {
        Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
    }
    // use the httpclient for any httpRequest
    return httpclient;
}
于 2013-02-05T23:09:45.970 回答
0

您的本地 JVM 或远程服务器可能没有所需的密码。到这里

https://www.oracle.com/java/technologies/javase-jce8-downloads.html

并下载包含以下内容的 zip 文件:US_export_policy.jar 和 local_policy.jar

替换现有文件(您需要在 JVM 中找到现有路径)。

在 Mac 上,我的路径就在这里。/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/security

这对我有用。

于 2020-02-12T20:46:47.120 回答