客户端必须传 server_hostname,否则握手大概率失败;服务端必须显式加载证书并设 server_side=true;弃用 ssl.wrap_socket(),统一使用 sslcontext 模式;证书 cn/san 必须匹配实际访问域名或 ip。

客户端必须传 server_hostname,否则握手大概率失败
不加 server_hostname 参数时,context.wrap_socket() 会跳过主机名验证,但现代服务(尤其是启用 SNI 的 HTTPS 或自建 TLS 服务)通常拒绝这种连接,现象是:ssl.SSLError: [SSL: WRONG_VERSION_NUMBER]、空响应,或直接断连。
即使你连的是 127.0.0.1,只要服务端证书的 Subject Alternative Name (SAN) 或 CN 写的是域名(如 localhost),就必须填对应值,不能填 IP 地址。
- 正确写法:
secure_sock = context.wrap_socket(sock, server_hostname="localhost") - 若用自签名证书且仅用于测试,可临时关闭验证:
context.check_hostname = False和context.verify_mode = ssl.CERT_NONE,但生产环境禁用 - 证书里没配
localhost?用openssl x509 -in cert.pem -text -noout检查 SAN 字段
服务端必须显式加载证书并设 server_side=True
只调 context.wrap_socket(client_socket, server_side=True) 而不提前 load_cert_chain(),会立刻报 ssl.SSLError: [SSL: SSL_HANDSHAKE_FAILURE]。常见漏点有三个:
-
certfile和keyfile路径必须存在、可读,推荐用绝对路径,避免相对路径引发FileNotFoundError - 上下文必须初始化为
ssl.Purpose.CLIENT_AUTH(即ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)或ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)),默认用途是客户端,无法接受入站握手 -
server_side=True不可省略——漏掉会导致ssl.SSLEOFError或 recv() 返回空字节
别再用 ssl.wrap_socket(),它已弃用
ssl.wrap_socket(sock, ...) 在 Python 3.12+ 已标记为弃用,运行时抛 DeprecationWarning,未来版本可能移除。所有新代码应统一走上下文模式:
- 客户端:用
ssl.create_default_context()创建上下文,再wrap_socket(..., server_hostname=...) - 服务端:用
ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)或ssl.create_default_context(ssl.Purpose.CLIENT_AUTH),再load_cert_chain(),最后wrap_socket(..., server_side=True) - 如需控制加密套件(例如禁用弱算法),调
context.set_ciphers("ECDHE-ECDSA-AES256-GCM-SHA384"),而不是操作底层 socket
证书生成必须匹配使用场景
自签名证书最常卡在 CN/SAN 不匹配。现象是连接建立后立即断开,或 recv() 返回空——根本原因不是代码错,而是证书本身无效。
SkillSub Pro - Python 题解与代码注释双功能技能功能概述SkillSub Pro - Python 题解与代码注释双功能技能是一项面向实际任务的技能,主要用于SkillSub Pro 是一个 Python 题解生成与代码注释的 双功能合体技能 ,专为学生、算法学习者和开发者设计;✅ 一个技能,两种用途 :;核心要点📝 题解模式 :输入题目/题号,自动生成完整 Python 题解(含详细注释、解题思路、复杂度分析);💬 注释模式 :输入 Python 代码,自动添加详细中。它将相关步骤、
生成时务必用:
openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 365 -subj "/CN=localhost"
注意:/CN=localhost 是必须项;若服务监听 127.0.0.1 但证书 CN 是 example.com,客户端即使填 server_hostname="127.0.0.1" 也会失败(除非关验证)。
更稳妥的做法是加 SAN:
openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 365 -subj "/CN=localhost" -addext "subjectAltName=DNS:localhost,IP:127.0.0.1"
证书细节永远比代码逻辑更容易出问题。调试前先确认证书是否真的覆盖了你要连的 host 名。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










