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

如何配置Python SSL服务器密码套件匹配客户端(无需证书)

问题解决方法

核心原因

你遇到的ssl.SSLError: [SSL: NO_SHARED_CIPHER] no shared cipher错误本质是:默认的ssl.Purpose.CLIENT_AUTH上下文要求服务器必须配置证书,而你没有提供任何证书,导致服务器无法和curl协商出可用的加密套件;同时现代curl默认禁用了匿名TLS套件,就算你指定了普通套件,没有证书也无法完成握手。

方案1:使用匿名TLS套件(无需证书)

修改代码使用支持匿名加密的上下文,同时curl需要显式允许匿名套件:

修改后的代码

import socket, ssl

# 创建支持匿名套件的上下文
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
# 启用匿名加密套件
context.set_ciphers("ADH-AES256-GCM-SHA384:ADH-CHACHA20-POLY1305-SHA256")
# 关闭客户端证书验证(因为是匿名模式)
context.verify_mode = ssl.CERT_NONE

bindsocket = socket.socket()
bindsocket.bind(("", 443))
bindsocket.listen(5)

while True:
    newsocket, fromaddr = bindsocket.accept()
    connstream = context.wrap_socket(newsocket, server_side=True)
    try:
        data = connstream.recv(1024)
        if not data:
            break
        # 可选:返回简单HTTP响应让curl能看到结果
        connstream.send(b"HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World!")
    except ssl.SSLError as e:
        print(f"SSL错误: {e}")
    finally:
        try:
            connstream.shutdown(socket.SHUT_RDWR)
        except:
            pass
        connstream.close()

对应的curl命令

需要加上--ciphers参数指定匿名套件,同时因为没有证书,要跳过证书验证:

curl -v --insecure --ciphers ADH-AES256-GCM-SHA384 https://localhost:443/

方案2:自动生成临时自签名证书(无需手动准备证书文件)

如果你不想用匿名套件(匿名套件安全性较低),可以在代码中自动生成临时的自签名证书,不需要提前创建证书文件:

修改后的代码

import socket, ssl
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.backends import default_backend
import datetime

# 生成临时RSA密钥对
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
    backend=default_backend()
)

# 生成自签名证书
subject = issuer = x509.Name([
    x509.NameAttribute(NameOID.COUNTRY_NAME, "CN"),
    x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Beijing"),
    x509.NameAttribute(NameOID.LOCALITY_NAME, "Beijing"),
    x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Test Org"),
    x509.NameAttribute(NameOID.COMMON_NAME, "localhost"),
])

cert = x509.CertificateBuilder().subject_name(
    subject
).issuer_name(
    issuer
).public_key(
    private_key.public_key()
).serial_number(
    x509.random_serial_number()
).not_valid_before(
    datetime.datetime.utcnow()
).not_valid_after(
    datetime.datetime.utcnow() + datetime.timedelta(days=365)
).add_extension(
    x509.SubjectAlternativeName([x509.DNSName("localhost")]),
    critical=False,
).sign(private_key, hashes.SHA256(), default_backend())

# 创建SSL上下文并加载生成的证书和密钥
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(
    certfile=None,
    keyfile=None,
    cert_data=cert.public_bytes(serialization.Encoding.PEM),
    key_data=private_key.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.PKCS8,
        encryption_algorithm=serialization.NoEncryption()
    )
)

bindsocket = socket.socket()
bindsocket.bind(("", 443))
bindsocket.listen(5)

while True:
    newsocket, fromaddr = bindsocket.accept()
    connstream = context.wrap_socket(newsocket, server_side=True)
    try:
        data = connstream.recv(1024)
        if not data:
            break
        # 返回HTTP响应
        connstream.send(b"HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World!")
    except ssl.SSLError as e:
        print(f"SSL错误: {e}")
    finally:
        try:
            connstream.shutdown(socket.SHUT_RDWR)
        except:
            pass
        connstream.close()

对应的curl命令

只需要跳过证书验证即可(因为是自签名证书):

curl -v --insecure https://localhost:443/

注意事项

  • 匿名TLS套件的安全性较低,仅适合测试场景,生产环境绝对不能使用。
  • 自动生成的自签名证书仅用于测试,生产环境需要使用受信任的CA颁发的证书。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 22:44:50