HTTPS:如何支持所有 SSL/TLS 协议和密码套件?

HTTPS: How to support all SSL/TLS protocols and cipher suits?

我正在开发一个需要向各种服务器发出 HTTPS 请求的爬虫。因此,我希望我的爬虫能够支持所有可能的 protocols/ciphers.

我目前正在使用 Java 8,但愿意升级(我认为这不重要)。

我按如下方式创建了 SSLContext:

SSLContext sslContext = SSLContext.getInstance("TLSv1.2");

我想每个支持 TLSv1.3 的服务器也都支持 1.2。

这会向后兼容吗?即支持 TLS 1.1/1.0 和 SSL?

(顺便说一句,如今甚至还在使用 SSL 吗?)

我还需要做什么才能保证 SSL/TLS 握手成功?

谢谢!

Because of that, I'd like my crawler to support all possible protocols/ciphers.
I'm currently using Java 8 but willing to upgrade (don't think it matters).

I guess that every server that supports TLSv1.3 supports 1.2 as well.
Is this going to be backward compatible? i.e. support TLS 1.1/1.0 and SSL?
(Is SSL even being used nowadays btw?)

是的,至少在不久的将来几乎所有支持 1.3 的人也将支持 1.2,除了一些专门为测试 1.3 兼容性而设置的站点。 (我敢打赌,许多人甚至会继续支持 1.1,例如 PCI 仍然允许它,尽管不情愿,但你不需要那个;任何支持 1.1 的 Java 也支持 1.2。)TLSv1.2 上下文支持低版本(如果允许,见下文),默认的TLS上下文也支持1.2和更低的in j8(默认在j7 支持 1.1 和 1.2 客户端)。

没有人应该使用 SSLv3 since 2016 at latest 和 Java 版本,因为 2014-12 年的 j8u31 已被配置为禁止它,尽管如果您更改配置以允许它,代码仍然存在.请参阅 JRE/lib/security/java.security 中的 jdk.tls.disabledAlgorithms 条目(对于 j8)或 JAVA/conf/security/java.security(对于 j9 以上)。注意这种'disable'不能通过代码调用SSLSocket.setEnabledProtocols和相关方法来逆转,只能通过更改配置或启动时的安全属性;相反,协议 'disabled' 通过选择上下文可以在需要时启用,反之亦然。

自世纪之交以来,应该没有人在使用 SSLv2(2000 年或 2001 年,取决于您的迂腐程度;在这一点上,差异无关紧要)。 Java 无论如何都没有(也从来没有)实施它。

此时使用 TLSv1.0 是有争议的。从理论上讲,它容易受到 BEAST 的攻击,但事实证明这毕竟不是什么危险,现在通过 1/n 拆分应用程序数据可以进一步缓解。由于 Java 默认包含它,我不会费心删除它,但您可能会对您发现实际上 select 它的任何服务器有点警惕。

您无法支持所有密码套件,因为 Java 并未全部实现;幸运的是你不需要。 Internet 上没有人使用 PSK(1.3 中用于恢复的变体除外)SRP 或 Kerberos; Java 仅实现最后一个。可能 none 或很少 需要 Camellia SEED ARIA IDEA 或 AES-CCM,none 其中 Java 实现(至少在标准中cryptoproviders),尽管您可能会遇到一些至少支持其中一些(如果提供的话)。没有人应该支持 RC4、'export' 套件、'eNULL' 和 single-DES; Java 版本再次禁止 java.security 中的 RC4,因为 2015-08 年的 8u60 和 default-disabled 其他很长一段时间,以及 'anonymous' 套件(又名 'aNULL')。最后一个是我唯一会考虑改变的;我可以想象 运行 public 服务器没有证书身份验证的罕见但合理的情况,但在其他方面是安全的。

但是除了协议和密码之外,还有其他安全参数可以阻止连接。特别是 Java 现在被配置为拒绝使用太短而不安全的密钥或参数的握手,或者使用 MD5 签名的证书(为此目的而损坏),即使这些是在两个端点都可接受的密码套件中使用的. disabledAlgorithms 中的这些设置与 jdk.certpath.disabledAlgorithms 中的证书 中的设置类似,您可能需要放宽它们。使用弱化参数的连接存在一定的风险,但由于您可能没有任何敏感信息可发送到未知服务器,并且无论如何都不会信任您从他们那里收到的任何信息,因此这种妥协可能不会一个问题。

接下来可能最大的是证书验证。您将 运行 进入许多使用实际上无效的证书的站点,以及更多无法根据标准 Java 信任库 JRE/lib/security/cacerts 或类似 [=82] 验证的站点=]' 或 Mozilla 的。由于您可能不关心您实际上是从真实的还是合法的服务器获取数据,因此您可以通过使用非默认 TrustManager 来忽略证书错误,它只是 returns 成功而无需实际验证服务器的证书链根本。如果你在 SO 上搜索其他问题,你可以找到大约一百个有人在 'just cut&paste this TrustManager to fix all problems without any thought, understanding or effort' Java 中提出 'solving' TLS 或 https 问题。在许多情况下,这是由实际上并不了解 TLS 的人提出的,用于首先不是证书问题的问题,因此 'solution' 无济于事,只会使系统完全不安全,如果并且当实际问题得到解决时。我认为你的问题是我看到的第一个问题,这个解决方案实际上是合适的。

最后,TLS 中有一个名义上可选的功能,即服务器名称指示 (SNI),现在许多服务器都需要它,尤其是 CDN、WAF、IDS/IPSes 和处理多个域流量的类似功能。根据您用来建立连接的 API(s) 和选项,旧版本的 Java 并不总是发送 SNI。然而,recent j8 及更高版本应该这样做,除非你故意禁用它——你可能会发现一些损坏的服务器,你 do 需要禁用它.