HttpGet with HTTPS : SSLPeerUnverifiedException

2022-09-01 03:53:02

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

线程“main” 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 );

如何禁止显示或删除此错误?


答案 1

注意:不要在生产代码中执行此操作,而是使用 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;
    }
}

答案 2

这个答案紧跟着猫头鹰和马特的回应。它适用于 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