阻止 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_client 和 s_server 在您执行 openssl s_client -connect ... -tls 之类的操作时所做的。您可以在<openssl src dir>/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,因为我需要一个新的连接。