如何在Python ssl中获取自定义配置的TLS客户端支持协议版本
刚好之前研究过这个问题,Python的ssl模块确实没有像get_ciphers()那样直接返回支持协议版本的API,但我们可以通过两种方式来获取:
方法一:解析上下文的options参数
当你通过context.options排除协议版本时,本质是设置了ssl.OP_NO_*系列的常量。我们可以通过对比这些常量是否被设置,反向推导出当前上下文支持的协议版本。
示例代码:
import ssl def get_supported_protocols(context): # 映射协议名称到对应的禁用选项 protocol_option_map = { "SSLv2": ssl.OP_NO_SSLv2, "SSLv3": ssl.OP_NO_SSLv3, "TLSv1": ssl.OP_NO_TLSv1, "TLSv1.1": ssl.OP_NO_TLSv1_1, "TLSv1.2": ssl.OP_NO_TLSv1_2, "TLSv1.3": ssl.OP_NO_TLSv1_3 } supported_protocols = [] for proto_name, opt_flag in protocol_option_map.items(): # 如果该禁用选项未被设置,说明支持对应协议 if not (context.options & opt_flag): supported_protocols.append(proto_name) return supported_protocols # 测试:创建上下文并排除TLSv1和TLSv1.1 ctx = ssl.create_default_context() ctx.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 print("当前支持的协议版本:", get_supported_protocols(ctx))
注意事项:
- Python的
create_default_context()默认已经禁用了SSLv2和SSLv3(出于安全考虑),所以即使代码中没显式排除,这两个协议也不会出现在结果里。 - 不同Python版本支持的协议范围可能不同,比如TLSv1.3需要Python 3.7及以上版本,且底层依赖OpenSSL 1.1.1+。
方法二:通过实际握手测试验证
如果想要更准确的结果(比如考虑底层OpenSSL库的限制),可以尝试和支持多版本的服务器握手,逐个验证协议是否可用。
示例代码:
import ssl import socket def is_protocol_supported(target_protocol): # 创建仅允许目标协议的上下文 ctx = ssl.create_default_context() # 禁用所有其他协议 if target_protocol == "TLSv1": ctx.options |= ssl.OP_NO_TLSv1_1 | ssl.OP_NO_TLSv1_2 | ssl.OP_NO_TLSv1_3 | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 elif target_protocol == "TLSv1.1": ctx.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_2 | ssl.OP_NO_TLSv1_3 | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 elif target_protocol == "TLSv1.2": ctx.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 | ssl.OP_NO_TLSv1_3 | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 elif target_protocol == "TLSv1.3": ctx.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 | ssl.OP_NO_TLSv1_2 | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 try: # 连接到Cloudflare的公共DNS服务器(支持多种TLS版本) with socket.create_connection(("1.1.1.1", 443)) as sock: with ctx.wrap_socket(sock, server_hostname="1.1.1.1") as ssl_sock: return True, ssl_sock.version() except ssl.SSLError: return False, None # 检测所有常见协议版本 test_protocols = ["TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"] supported = [] for proto in test_protocols: success, actual_version = is_protocol_supported(proto) if success: supported.append(actual_version) print("实际支持的协议版本:", supported)
优缺点:
- 优点:能真实反映系统实际支持的协议(比如如果底层OpenSSL不支持TLSv1.3,即使Python配置允许,也会被检测出来)。
- 缺点:需要网络连接,且依赖测试服务器对对应协议的支持。
内容的提问来源于stack exchange,提问作者user9371654
相关产品推荐
相关产品推荐

