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

如何强制Java SSLContext及Jersey客户端使用TLSv1.1协议

问题根因
  • 高版本JDK(JDK 8u292、JDK 11及以上)默认在java.security配置的jdk.tls.disabledAlgorithms中加入了TLSv1、TLSv1.1,即使你调用SSLContext.getInstance("TLSv1.1")创建上下文,JDK也会默认禁用该版本协议的握手。
  • Jersey 1.x的HTTPSProperties仅负责给HttpsURLConnection设置SSLSocketFactory和HostnameVerifier,不会对SSLSocket的启用协议做限制,你指定的TLSv1.1上下文不会限制客户端仅用该版本发起握手,默认仍会尝试使用最高可用的协议版本,或者被JDK全局配置禁用导致握手失败。
  • 你配置的https.protocols系统属性仅对JDK默认的SSLSocketFactory生效,自定义SSLContext后该配置会被忽略。

你使用SSLContext.getInstance("TLS")时可以正常运行,是因为此时客户端会使用JDK默认启用的高版本协议(TLSv1.2/TLSv1.3),和服务端支持的协议匹配,所以握手成功。

解决方案

步骤1:解除客户端JDK的TLSv1.1禁用限制

打开客户端JDK的安全配置文件:

  • JDK 8路径:jre/lib/security/java.security
  • JDK 11及以上路径:conf/security/java.security
    找到jdk.tls.disabledAlgorithms配置项,删除其中的TLSv1、TLSv1.1条目并保存。

步骤2:自定义SSLSocketFactory强制指定协议版本

因为Jersey 1.x没有提供直接配置启用协议的入口,你需要自定义SSLSocketFactory包装类,强制所有创建的SSLSocket仅使用TLSv1.1协议:

import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;

public class FixedTLSVersionSocketFactory extends SSLSocketFactory {
    private final SSLSocketFactory delegateFactory;
    private static final String[] ALLOWED_PROTOCOLS = {"TLSv1.1"};

    public FixedTLSVersionSocketFactory(SSLSocketFactory delegate) {
        this.delegateFactory = delegate;
    }

    private Socket configureTLSVersion(Socket socket) {
        if (socket instanceof SSLSocket) {
            ((SSLSocket) socket).setEnabledProtocols(ALLOWED_PROTOCOLS);
        }
        return socket;
    }

    @Override
    public Socket createSocket() throws IOException {
        return configureTLSVersion(delegateFactory.createSocket());
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException {
        return configureTLSVersion(delegateFactory.createSocket(host, port));
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
        return configureTLSVersion(delegateFactory.createSocket(host, port, localHost, localPort));
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return configureTLSVersion(delegateFactory.createSocket(host, port));
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        return configureTLSVersion(delegateFactory.createSocket(address, port, localAddress, localPort));
    }

    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        return configureTLSVersion(delegateFactory.createSocket(s, host, port, autoClose));
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return delegateFactory.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return delegateFactory.getSupportedCipherSuites();
    }
}

步骤3:修改Jersey客户端配置

由于HTTPSProperties仅接受SSLContext作为参数,选择自定义URLConnectionClientHandler来设置自定义的SocketFactory的方案更稳定:

import com.sun.jersey.client.urlconnection.URLConnectionClientHandler;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.net.HttpURLConnection;

public class TLSConfiguredClientHandler extends URLConnectionClientHandler {
    private final HostnameVerifier hostnameVerifier;
    private final FixedTLSVersionSocketFactory socketFactory;

    public TLSConfiguredClientHandler(HostnameVerifier hv, SSLContext sslContext) {
        this.hostnameVerifier = hv;
        this.socketFactory = new FixedTLSVersionSocketFactory(sslContext.getSocketFactory());
    }

    @Override
    protected void modifyConnection(HttpURLConnection connection) {
        if (connection instanceof HttpsURLConnection) {
            HttpsURLConnection httpsConn = (HttpsURLConnection) connection;
            httpsConn.setHostnameVerifier(hostnameVerifier);
            httpsConn.setSSLSocketFactory(socketFactory);
        }
        super.modifyConnection(connection);
    }
}

最后创建Jersey客户端时使用自定义的Handler即可:

SSLContext context = SSLContext.getInstance("TLSv1.1");
context.init(null, trustAll, new SecureRandom());
Client client = new Client(new TLSConfiguredClientHandler(hv, context));

内容的提问来源于stack exchange,提问作者Philippe Bertrand

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 15:18:03