【问题标题】:Prevent TLS version negotiation?阻止 TLS 版本协商?
【发布时间】:2016-05-03 16:28:58
【问题描述】:

我正在尝试寻找一种方法来阻止基于 OpenSSL 的服务器 (1.0.2g) 要求客户端从 TLS1.0 迁移到 TLS1.2。

这是一个专有服务器。我需要通过 openssl 直接通过 openssl API 调用、OP 标志、编译选项等来执行此操作。

我无权修改连接到我的服务器的客户端。这个特定的客户端目前包含相当一部分流量到我的服务器,但有一个错误导致它在协商后有效地挂起。

如果我的服务器是针对旧版本的 OpenSSL(例如 1.0.0d)编译的,则服务器不会尝试将协议提升到 TLS1.2,而是保持在 TLS1.0,一切正常。

不过,出于安全原因,我需要迁移到最新版本的 OpenSSL。有没有办法阻止服务器要求使用 TLS1.0 的客户端迁移到 TLS1.2,同时仍然允许 TLS1.2 客户端继续使用 TLS1.2?

(这些较旧的客户端已被弃用,最终将消失。较新的客户端已默认使用 TLS1.2)

【问题讨论】:

  • 这个问题的答案可能取决于您使用的服务器(例如 Apache、nginx、_etc);是哪一个?
  • 这是一个专有服务器。解决方案必须通过 openssl API 调用、OP 标志、编译选项等实现。

标签: openssl protocols tls1.2


【解决方案1】:

阻止 TLS 版本协商...

有一个根本性的误解正在发生。 TLS 版本不是协商本身

发送ClientHello 时,会有一个版本的 TLS,仅此而已。客户端的 TLS 协议版本通常称为ClientHello.client_version。还有一个ServerHello 和一个ServerHello.server_version

来自RFC 5246, The Transport Layer Security (TLS) Protocol Version 1.2,第 40 页:

struct {
    ProtocolVersion client_version;
    Random random;
    SessionID session_id;
    CipherSuite cipher_suites<2..2^16-2>;
    CompressionMethod compression_methods<1..2^8-1>;
    select (extensions_present) {
        case false:
            struct {};
        case true:
            Extension extensions<0..2^16-1>;
    };
} ClientHello;

假设客户端功能齐全,客户端应该尝试 TLS 1.2。如果服务器连接失败,客户端会尝试 TLS 1.1。如果服务器连接失败,客户端会尝试 TLS 1.0。

多重客户端重试正是浏览器所做的,这也是TLS_FALLBACK_SCSV 来自RFC 7507, TLS Fallback Signaling Cipher Suite Value (SCSV) for Preventing Protocol Downgrade Attacks 的原因。 TLS_FALLBACK_SCSV 允许客户端检测攻击者何时试图强制对连接进行降级。

实际发生的情况是有一个记录层和一个有效负载层。记录层携带 TLS 有效负载,并允许在不具有该功能的传输上进行分段。客户端使用 SSLv3 记录层,以便它通过能力最低的中间件盒,以及 TLS 1.2 有效负载层(来自握手问候)以获得更强的加密。一些服务器将其解释为客户端能够通过 TLS v1.2 使用 SSL v3.0。

为了进一步搅浑水,还有一个与 Compression 相关的版本(如果可用)。所以可能会出现三个不同的版本。


我正在尝试寻找一种方法来阻止基于 OpenSSL 的服务器 (1.0.2g) 要求客户端从 TLS1.0 迁移到 TLS1.2。

好的,鉴于上面的讨论,服务器什么都不问。如果客户端在其ClientHello.client_version 中宣传 TLS v1.2,那么这就是服务器通过在其ServerHello.server_version 中响应相同版本来使用的内容。

认为您也许可以使用以下内容来获得您需要的东西。但是你需要彻底测试它,因为我怀疑它会导致相当多的互操作问题:

// Record and payload layer
const SSL_METHOD* method = TLSv1_method();
SSL_CTX* context = SSL_CTX_new(method);
...

以上是 OpenSSL 的测试程序 s_clients_server 在您执行 openssl s_client -connect ... -tls 之类的操作时所做的。您可以在&lt;openssl src dir&gt;/apps找到源代码。

如果您使用SSLv23_method,那么您将获得与 SSLv2 兼容的ClientHello,您需要按照 Jim 向您展示的方式进行操作。

另请参阅 OpenSSL wiki 上的 SSL/TLS Client


这是仅使用 TLS 1.0 的 HTTPS 连接的样子。对 Yahoo 的跟踪是使用 openssl s_client -connect www.yahoo.com:443 -tls1 -servername www.yahoo.com 创建的。我使用 Yahoo 而不是 Stack Overflow,因为我需要一个新的连接。

【讨论】:

  • 这很有帮助,谢谢。显然,我需要对问题的确切性质做更多的故障排除,但这里的信息(连同 RFC2246)是有帮助的。
【解决方案2】:

你在 SSL_CTX_new 中使用什么?

你可以

SSL_CTX_new(SSLv23_method())

然后

SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3)

现在仅支持 TLS 1.0 的客户端将使用 TLS 1.0。可以支持 TLS 1.2 的客户端将协商到 TLS 1.2。这不是你想要的吗?

我没有尝试过,但你可能可以:

SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1_1)

这消除了任何 TLS 1.1,只留下 1.0 或 1.2 作为选项。

【讨论】:

  • @async_fm 问题是 TLS1.0 客户端需要连接而不要求升级到 TLS1.2 和 TLS1.2 客户端正常工作。这是正确的答案。
【解决方案3】:

假设您可以访问源代码中的SSL_CTX,以下应该禁用对 TLS 1.2 的支持/提供):

SSL_CTX *ssl_ctx;

...

#ifdef SSL_OP_NO_TLSv1_2
/* Disable TLSv1.2 */
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_2);
#endif

同样,如果您出于任何原因需要禁用 TLSv1.1 的提供/使用,您将使用 SSL_OP_NO_TLSv1_1 选项(并且,根据您的 OpenSSL 版本,类似的 #ifdef 保护)。

希望这会有所帮助!

【讨论】:

  • 不幸的是,这不能满足我的需要。正如我在 OP 中提到的,我有以 TLS1.2 形式出现的客户端,它们应该能够继续使用 1.2。问题是当客户带着 1.0 进来,然后协商到 1.2。我正在尝试找到一种方法,允许以 TLS1.0 形式出现的客户端留在那里,而以 TLS1.2 形式出现的客户端仍将使用 1.2
  • 我不确定您所说的“协商”是什么意思;客户端请求协议版本,服务器告诉他们它支持的最高版本;然后由客户端决定是否使用更高的协议版本。听起来您需要在响应之前自行剖析ClientHello 消息,以确定您需要设置哪些SSL_CTX 选项。
  • 嗯。好,谢谢。我会深入研究那条路线,看看我能做什么。
  • 或者,您可以提供两个不同的端口(如果需要,通过代理):一个端口配置为普通/完整 TLSv1.2 et al;另一个为 TLSv1.0 配置,并且可能让您的 TLSv1.0 客户端连接到那个不同的 TCP 端点。
猜你喜欢
  • 2018-07-13
  • 2019-05-30
  • 1970-01-01
  • 2015-05-29
  • 2021-09-11
  • 1970-01-01
  • 2011-03-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多