使用TLS/SSL包装asyncio Stream时数据未解密的问题求助
问题原因与解决方案
核心问题
你手动通过ssl.wrap_socket包装客户端socket后,再传给asyncio.open_connection,但asyncio.open_connection接收已存在的sock参数时,会直接将其作为普通TCP套接字处理,不会执行SSL解密逻辑,因此StreamReader.read返回的是未经解密的TLS加密字节流,自然无法用UTF-8解码。
解决思路
不要手动包装socket,让asyncio原生处理SSL层。推荐使用asyncio.start_server并传入ssl上下文参数,由asyncio自动完成每个连接的SSL握手与数据解密。
修改后的服务端代码
async def handle_client(self, reader, writer): try: data = await reader.read(1024) if not data: return # 客户端断开连接 request = data.decode('utf-8') response = self.generateResponse(request) writer.write(response.encode('utf-8')) await writer.drain() finally: writer.close() await writer.wait_closed() async def runSocket(self): # 创建SSL上下文,指定为客户端认证用途 context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) context.load_cert_chain(certfile="tls\\server_certificate.pem", keyfile="tls\\server_private_key.pem") # 启动支持SSL的异步服务器 server = await asyncio.start_server( lambda r, w: self.handle_client(r, w), host="0.0.0.0", # 根据实际需求绑定主机 port=12345, # 替换为你的服务端口 ssl=context ) async with server: await server.serve_forever()
客户端代码修正
你的客户端代码存在拼写错误:data.enocode('utf-8')应为data.encode('utf-8'),修正后的代码:
def postRequest(data, hostname, port): context = ssl.create_default_context() context.check_hostname = False # 注意:生产环境建议不要关闭hostname检查,确保证书有效性 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server: encrypted_server = context.wrap_socket(server, server_hostname=hostname) encrypted_server.connect((hostname, port)) encrypted_server.send(data.encode('utf-8')) response = encrypted_server.recv(1024).decode('utf-8') return response
额外说明
- 使用
asyncio.start_server不仅能自动处理SSL,还能并发处理多个客户端连接,避免原代码中循环处理单连接的阻塞问题。 - 生产环境中,客户端请勿关闭
check_hostname,并确保使用可信的CA证书,避免中间人攻击。
内容的提问来源于stack exchange,提问作者atiya khodari
相关产品推荐
相关产品推荐

