通过任何 SSL 或 TLS 版本的 HTTPS 连接

Posted

技术标签:

【中文标题】通过任何 SSL 或 TLS 版本的 HTTPS 连接【英文标题】:HTTPS connection over any SSL or TLS versions 【发布时间】:2019-03-28 22:52:04 【问题描述】:

我正在尝试对其他服务器实施基于 SSL 的 HTTPS 连接。

我需要提供所有协议(TLSv1.0TLSv1.1TLSv1.2TLSv1.3),并且无论哪个可用或启用,它都应该能够自行协商该版本。

目前是这样的:

SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, /*some certs*/, new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

        String webServicePath =" https://google.com"  //suppose

        URL url = new URL(webServicePath); 

        HttpsURLConnection httpsCon = (HttpsURLConnection) url.openConnection(); 
        httpsCon.setRequestMethod("POST"); 
        httpsCon.setRequestProperty("Content-Type", "application/json");
        httpsCon.setRequestProperty("Content-Language", "en-US");
        httpsCon.setUseCaches(false);
        httpsCon.setDoInput(true);
        httpsCon.setDoOutput(true);
        httpsCon.setHostnameVerifier(new HostnameVerifier() 

            @Override
            public boolean verify(String hostname, SSLSession session) 
                return true;
            
        ); 
        httpsCon.connect(); 

我想要类似:SSLContext.getInstance("TLSv1.0, TLSv1.1, TLSv1.2"); 但我不确定此方法是否需要多个参数。

我找到了解决方案:Dhttps.protocols=TLSv1.2,TLSv1.1,TLSv1” 在启动Java VM时,或者在代码中,等效的系统属性指令是“System.setProperty(“https.protocols” , “TLSv1.2,TLSv1.1,TLSv1”)”。

我想在我的代码中以编程方式执行此操作,但我不知道如何。

我读到客户端和服务器通过 HELLO 消息进行协商,直到他们同意双方支持的协议版本。为了实现这种协商,我必须在源代码中实现它吗?

【问题讨论】:

“我正在尝试实现基于 SSL 的 HTTPS”。第一个建议:不要再说 SSL。这已被 20 年前创建的 TLS 所取代。 “无论哪个可用或启用,它都应该能够自行协商该版本”阅读有关 TLS1.3 的 RFC8446 的长篇文章,其中包含有关如何与 1.3 服务器和旧客户端互操作的大量章节或相反。有许多细节需要正确实施。 “我读到客户端和服务器通过 HELLO 消息进行协商,直到他们同意双方支持的协议版本。”这在 TLS 握手中称为 ServerHelloClientHello。所有这些都应该被你使用的 TLS 库抽象出来,从阅读它的文档开始。 @PatrickMevzek 感谢您的回复。实际上,我的代码正在访问 Web 服务,但不知道为什么我在 httpsCon.connect(); - java.lang.RuntimeException: javax.net.ssl 上遇到握手失败异常。 SSLHandshakeException:收到致命警报:handshake_failure。相同的代码在 PROD 上运行良好。首先我认为它的版本兼容性问题。 【参考方案1】:

这是可以做到的。但是你需要编写一些额外的代码。

创建自定义套接字工厂

public class CustomCipherFactory extends SSLSocketFactory 
   @Override
 public Socket createSocket(Socket arg0, String arg1, int arg2, boolean arg3)
     throws IOException 

    Socket socket = this.delegate.createSocket(arg0, arg1, arg2, arg3);
    SSLParameters p = ((SSLSocket)socket).getSSLParameters();
    p.setProtocols(new String[]  "TLSv1.3","TLSv1.2" );
   ((SSLSocket)socket).setSSLParameters(p);
   return socket;
 

将该套接字工厂设置为 httpsUrlConnection(这是一个静态方法,因此影响是全局的,除非您取消设置它)。

SSLContext ctx = SSLContext.getInstance("SSL");
SSLSocketFactory sf = new CustomCipherFactory(ctx.getSocketFactory());
HttpsURLConnection.setDefaultSSLSocketFactory(sf);

【讨论】:

以上是关于通过任何 SSL 或 TLS 版本的 HTTPS 连接的主要内容,如果未能解决你的问题,请参考以下文章

根据 URL 路径或 apache(mod_ssl) 中的特定服务设置 SSL/TLS 协议版本

SSL/TLS协议信息泄露漏洞(CVE-2016-2183)漏洞修复升级

在每个请求的.net HttpWebRequest上设置SecurityProtocol(Ssl3或TLS)

HTTPS 安全最佳实践之SSL/TLS部署

TLS协议的TLS握手协议

如何使用 TLS/SSL 确保 WebSocket 连接的安全