通过任何 SSL 或 TLS 版本的 HTTPS 连接
Posted
技术标签:
【中文标题】通过任何 SSL 或 TLS 版本的 HTTPS 连接【英文标题】:HTTPS connection over any SSL or TLS versions 【发布时间】:2019-03-28 22:52:04 【问题描述】:我正在尝试对其他服务器实施基于 SSL 的 HTTPS 连接。
我需要提供所有协议(TLSv1.0
、TLSv1.1
、TLSv1.2
、TLSv1.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 握手中称为ServerHello
和 ClientHello
。所有这些都应该被你使用的 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)漏洞修复升级