最直接方式是同时设置MinVersion: tls.VersionTLS12和MaxVersion: tls.VersionTLS13,仅设MinVersion而MaxVersion为0时Go会按当前最高支持版本处理,行为不明确且不稳定。

设置 tls.Config.MinVersion 和 MaxVersion
禁用 TLS 1.0/1.1 的最直接方式是显式限制协议版本范围,而不是依赖默认行为。Go 的 crypto/tls 默认允许 TLS 1.2 起,但旧版 Go(如 1.12 之前)可能仍接受 TLS 1.1,尤其在未显式配置时。
必须同时设置 MinVersion 和 MaxVersion,否则仅设其一可能被忽略或产生意外兼容性:
-
MinVersion: tls.VersionTLS12—— 拒绝任何低于 TLS 1.2 的握手请求 -
MaxVersion: tls.VersionTLS13—— 防止未来 TLS 1.4 等新版本引入未验证行为(可选,但推荐) - 不写
MaxVersion时,Go 会使用当前运行时支持的最高版本,可能随 Go 升级而变化,不利于稳定性
示例片段:
cfg := &tls.Config{
MinVersion: tls.VersionTLS12,
MaxVersion: tls.VersionTLS13,
}
避免 ssl_prefer_server_ciphers 的客户端陷阱
服务端常用 ssl_prefer_server_ciphers on 来控制密码套件优先级,但该逻辑在客户端不生效——tls.Config 中没有对应字段,且 Go 客户端默认按自身硬编码顺序协商,不“尊重”服务端偏好。
立即学习“go语言免费学习笔记(深入)”;
若你发现连接失败且怀疑是密码套件不匹配,真正有效的做法是显式指定 CipherSuites 列表,而非试图模拟服务端策略:
- 只保留前向保密强、无已知漏洞的套件,例如
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - 避开含
RC4、MD5、SHA1、DES、3DES的套件(Go 1.19+ 已移除 RC4 常量) - 注意:DHE 套件需服务端 DH 参数 ≤1024 位才可能成功,否则握手失败;ECDHE 更可靠
别用 InsecureSkipVerify 绕过协议检查
有些开发者遇到 remote error: tls: handshake failure 后,第一反应是加 InsecureSkipVerify: true,但这完全无效——该字段只跳过证书链和主机名校验,不影响协议版本协商过程。
它甚至可能掩盖真实问题:比如服务端只支持 TLS 1.1,而客户端强制要求 TLS 1.2,此时即使跳过证书验证,连接仍会在 ClientHello 阶段就断开,错误仍是 handshake failure。
真正该做的是:
- 用
openssl s_client -connect host:port -tls1_1实测服务端实际支持的协议 - 确认你的 Go 版本 ≥ 1.12(对 TLS 1.3 支持更稳定),并检查是否意外覆盖了
MinVersion - 如果服务端老旧且无法升级,唯一合规路径是协调对方禁用 TLS 1.0/1.1,而非在客户端降级
Go 1.7+ 的 Renegotiation 字段不是协议版本控制项
看到 Renegotiation: tls.RenegotiateNever 就以为“这能关掉 TLS 1.0”是常见误解。该字段只控制重协商行为(即连接建立后是否允许再次协商参数),与协议版本无关。
TLS 重协商在 TLS 1.3 中已被彻底移除,所以禁用它对现代服务是安全加固,但不会影响 TLS 1.0/1.1 是否被协商。如果你的连接卡在 TLS 1.0 握手阶段,调这个字段毫无作用。
真正需要警惕的是:Go handshake failure 还是 server requested renegotiation。


















