You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python ssl模块创建匿名DH TLS套接字并实现防凭证转发的安全认证

关于P2P协议中无证书TLS连接及挑战响应认证的解决方案

问题1:无证书TLS连接的实现

要在Python中创建无需证书的TLS连接,可采用**匿名Diffie-Hellman(ADH)**密码套件——这类套件仅通过DH交换会话密钥,不依赖证书完成身份验证,刚好匹配你的需求。

实现步骤

  1. 创建SSLContext时指定兼容现代TLS的协议版本,同时禁用证书验证(因为无需证书)。
  2. 显式声明支持的ADH密码套件(部分默认套件列表可能不包含ADH)。

代码示例

服务器端

import socket
import ssl

# 创建服务器上下文,禁用证书验证
server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
server_context.check_hostname = False
server_context.verify_mode = ssl.CERT_NONE
# 指定ADH加密套件,这里选用AES256加密的版本
server_context.set_ciphers('ADH-AES256-SHA')

# 绑定Socket并包装SSL层
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
    sock.bind(('localhost', 8443))
    sock.listen(1)
    with server_context.wrap_socket(sock, server_side=True) as ssl_sock:
        conn, addr = ssl_sock.accept()
        print(f"已连接节点:{addr}")
        # 后续执行挑战响应认证

客户端

import socket
import ssl

# 创建客户端上下文,禁用证书验证
client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
client_context.check_hostname = False
client_context.verify_mode = ssl.CERT_NONE
client_context.set_ciphers('ADH-AES256-SHA')

# 连接服务器并包装SSL层
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
    with client_context.wrap_socket(sock, server_hostname='localhost') as ssl_sock:
        ssl_sock.connect(('localhost', 8443))
        print("已连接服务器节点")
        # 后续执行挑战响应认证

注意:ADH套件本身不提供身份验证,必须依赖后续的挑战响应确认对方身份,否则中间人可轻松拦截会话。

问题2:防中间人转发的挑战响应认证

要排除中间人转发凭证的风险,挑战响应必须绑定当前TLS会话的唯一性信息,同时采用双向认证(双方都发起挑战)。核心思路是:挑战信息包含会话专属的随机值或会话派生数据,确保中间人无法复用之前的签名结果。

具体实现流程

  1. 每个节点预先生成ECDSA密钥对(私钥仅本地保存,公钥可在P2P网络中交换或预先共享)。
  2. TLS握手完成后,双方执行双向挑战:
    • 节点A生成随机nonce,附加TLS会话主密钥的SHA256哈希值(或会话ID哈希),将组合数据发送给节点B。
    • 节点B用自身ECDSA私钥对组合数据签名,将签名和公钥发送给节点A。
    • 节点A用节点B的公钥验证签名,确认签名有效且哈希值匹配当前会话,完成对B的认证。
    • 节点B重复上述流程,发起对节点A的挑战。

关键细节

  • 加入会话主密钥哈希:中间人无法获取两端的会话主密钥,因此无法生成匹配当前会话的签名,即使拿到旧签名也无法复用。
  • 双向认证:避免单向认证时,中间人冒充一方转发挑战的情况。

代码片段(ECDSA挑战响应)

import os
import hashlib
from cryptography.hazmat.primitives.asymmetric import ecdsa
from cryptography.hazmat.primitives import serialization, hashes

# 每个节点本地生成ECDSA密钥对
private_key = ecdsa.generate_private_key(ecdsa.SECP256R1())
public_key = private_key.public_key()

def generate_challenge(ssl_sock):
    # 生成16字节随机nonce
    nonce = os.urandom(16)
    # 计算会话主密钥的SHA256哈希
    session_hash = hashlib.sha256(ssl_sock.get_session().master_key).digest()
    # 组合挑战数据
    return nonce, nonce + session_hash

def sign_challenge(private_key, challenge):
    # ECDSA签名挑战数据
    return private_key.sign(challenge, ecdsa.ECDSA(hashes.SHA256()))

def verify_challenge(public_key, challenge, signature):
    # 验证签名有效性
    try:
        public_key.verify(signature, challenge, ecdsa.ECDSA(hashes.SHA256()))
        return True
    except Exception:
        return False

执行时,双方互相发送挑战、签名,验证通过后即可确认身份,排除中间人攻击。


内容的提问来源于stack exchange,提问作者Antti Haapala

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 18:43:24