You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java 1.6+HttpClient4.2.3禁用SSL证书验证解决方案求助

问题描述

架构限制下维护的Maven Web应用用的是旧技术栈:

  • Java 1.6
  • HttpClient 4.2.3(基于DefaultHttpClient)

业务流程分两步:

  1. 发送HTTPS POST请求获取JWT Token
  2. 携带Token发送HTTPS GET请求跳转至签名表单站点

现在遇到的问题:点击获取Token的跳转链接时,抛出javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated错误。

之前试过一个自定义信任所有证书的方案,但无效,代码如下:

private DefaultHttpClient getDefaultHttpClient(DefaultHttpClient httpClient) throws NoSuchAlgorithmException, KeyManagementException {
        
        SSLContext sslContext = null;
        sslContext = SSLContext.getInstance("SSL");

        // set up a TrustManager that trusts everything
        sslContext.init(null, new TrustManager[] { new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                System.out.println("getAcceptedIssuers =============");
                return null;
            }

            public void checkClientTrusted(X509Certificate[] certs, String authType) {
                System.out.println("checkClientTrusted =============");
            }

            public void checkServerTrusted(X509Certificate[] certs, String authType) {
                System.out.println("checkServerTrusted =============");
            }
        } }, new SecureRandom());

        final SSLSocketFactory theSslSocketFactory = new SSLSocketFactory(sslContext);

        final Scheme theHttpsScheme = new Scheme("https", theSslSocketFactory, 443);
        httpClient.getConnectionManager().getSchemeRegistry().register(theHttpsScheme);
        
        return httpClient;
    }

原请求代码:

DefaultHttpClient httpClient = new DefaultHttpClient();
try {
  HttpPost postRequest = new HttpPost(endpointAddress);
  StringEntity input = new StringEntity(jo.toString(), "UTF-8");
  input.setContentType("application/json");
  postRequest.setEntity(input);

  HttpResponse response = httpClient.execute(postRequest);
  HttpEntity httpEntity = response.getEntity();
  String responseString = EntityUtils.toString(httpEntity);
  JSONObject resultObj = new JSONObject(responseString);
  String tokenId = resultObj.getString("token");
}catch(Exception e) {
  e.printStackTrace();
}finally {
  httpClient.getConnectionManager().shutdown();
}

可行解决方案

方案一:修复自定义信任证书的配置

之前的方案有两个核心问题:一是getAcceptedIssuers返回null,Java 1.6的SSL实现不兼容;二是未禁用主机名验证。修改后的代码如下:

private DefaultHttpClient createTrustAllHttpClient() throws NoSuchAlgorithmException, KeyManagementException {
    // 自定义信任所有证书的TrustManager
    X509TrustManager trustAllManager = new X509TrustManager() {
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            // 返回空数组而非null,适配Java 1.6的SSL实现
            return new X509Certificate[0];
        }

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

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

    // 用TLS初始化SSLContext,比SSL协议更安全
    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, new TrustManager[]{trustAllManager}, new SecureRandom());

    // 创建SSLSocketFactory并禁用主机名验证
    SSLSocketFactory sslSocketFactory = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

    // 新建HttpClient实例,避免原有连接缓存导致配置不生效
    DefaultHttpClient httpClient = new DefaultHttpClient();
    SchemeRegistry schemeRegistry = httpClient.getConnectionManager().getSchemeRegistry();
    // 替换默认的https协议配置
    schemeRegistry.register(new Scheme("https", 443, sslSocketFactory));

    return httpClient;
}

在请求代码中使用该方法创建HttpClient:

try {
    DefaultHttpClient httpClient = createTrustAllHttpClient();
    HttpPost postRequest = new HttpPost(endpointAddress);
    StringEntity input = new StringEntity(jo.toString(), "UTF-8");
    input.setContentType("application/json");
    postRequest.setEntity(input);

    HttpResponse response = httpClient.execute(postRequest);
    HttpEntity httpEntity = response.getEntity();
    String responseString = EntityUtils.toString(httpEntity);
    JSONObject resultObj = new JSONObject(responseString);
    String tokenId = resultObj.getString("token");
}catch(Exception e) {
    e.printStackTrace();
}

方案二:导入服务器证书到Java信任库(推荐,更安全)

如果不想禁用证书验证,可将目标服务器的SSL证书导入Java 1.6的默认信任库:

  1. 导出服务器证书:
    执行以下命令将证书导出到文件:
    openssl s_client -connect 目标域名:443 < /dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > server.crt
    
  2. 导入到信任库:
    keytool -import -alias target-server -keystore $JAVA_HOME/jre/lib/security/cacerts -file server.crt
    
    默认密码为changeit,按提示确认导入即可。
  3. 重启应用,HttpClient会自动信任该证书,无需修改代码。

方案三:指定自定义信任库

如果无法修改系统默认信任库,可在代码中指定自定义信任库:

private DefaultHttpClient createCustomTrustStoreHttpClient(String trustStorePath, String trustStorePassword) throws Exception {
    KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
    FileInputStream instream = new FileInputStream(new File(trustStorePath));
    try {
        trustStore.load(instream, trustStorePassword.toCharArray());
    } finally {
        instream.close();
    }

    SSLSocketFactory sslSocketFactory = new SSLSocketFactory(trustStore);
    DefaultHttpClient httpClient = new DefaultHttpClient();
    SchemeRegistry schemeRegistry = httpClient.getConnectionManager().getSchemeRegistry();
    schemeRegistry.register(new Scheme("https", 443, sslSocketFactory));

    return httpClient;
}

使用时传入自定义信任库的路径和密码,信任库需提前导入目标服务器的证书。


内容的提问来源于stack exchange,提问作者Elgün Şükürov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 12:35:26