我正在尝试构建一个库来构建一个库来制作 Gemini(协议)服务器,到目前为止,除了一件事之外,我一切正常。
在
gemini 规范
中,它说客户端能够用 tls 发送他们的证书以进行识别等,但是当在 python 中我收到证书时,我收到一个关于它如何自签名的错误
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate (_ssl.c:1000)
这就是我设置上下文的方式。
...
self.context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
self.context.load_cert_chain(certfile=certfile, keyfile=keyfile)
ssl.context.verify_mode = ssl.CERT_OPTIONAL # optional because the spec says clients don't have to
...
现在我通过使用
.load_verify_locations
加载客户端证书来缓解这个问题,但是当您实际公开运行服务器时,这显然不起作用。
我希望它甚至不会检查客户端证书是否是自签名的,但它确实如此然后你会期望能够将其关闭,但似乎我不能?我已经阅读了很多 python SSL 文档,但仍然无法弄清楚。
你几乎完成了解决方案了!问题在于你理解了
ssl.CERT_OPTIONAL
的工作原理。
虽然看起来它应该完全跳过客户端证书验证,但实际情况是,它仍然会 请求 证书(如果客户端没有提供,则不会报错)。但是,如果提供了证书,它 会 像你看到的那样尝试验证证书。
你想要的是完全禁用客户端证书验证。不幸的是,标准库
ssl
模块中没有直接的方法可以做到这一点。
但是,你有几个选择:
-
接受警告:
你可以使用
warnings
模块来捕获并忽略SSLCertVerificationError
。这不是最优雅的解决方案,但它可以工作。
```python import warnings import ssl
# ... 你的代码 ...
with warnings.catch_warnings(): warnings.simplefilter("ignore", ssl.SSLCertVerificationError) try: # 在这里执行涉及客户端证书的 SSL 操作 except ssl.SSLCertVerificationError: pass ```
-
子类化
ssl.SSLContext
: 你可以创建ssl.SSLContext
的子类并覆盖get_verify_mode()
方法以始终返回ssl.CERT_NONE
。
```python import ssl
class NoCertVerificationContext(ssl.SSLContext): def get_verify_mode(self): return ssl.CERT_NONE
# ... 你的代码 ...
self.context = NoCertVerificationContext(ssl.Purpose.CLIENT_AUTH) self.context.load_cert_chain(certfile=certfile, keyfile=keyfile) ```
-
使用第三方库:
诸如
cryptography
之类的库提供了对 SSL 的更精细控制,包括禁用证书验证的能力。
```python from cryptography import x509 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.x509.oid import NameOID
# ... 生成自签名证书(如果需要)...
# 加载证书和私钥 with open("certificate.pem", "rb") as f: certificate = x509.load_pem_x509_certificate(f.read(), default_backend()) with open("key.pem", "rb") as f: private_key = serialization.load_pem_private_key( f.read(), password=None, backend=default_backend() )
# 创建 SSL 上下文 context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) context.load_cert_chain(certificate=certificate, private_key=private_key)
# 禁用证书验证 context.verify_mode = ssl.CERT_NONE
# ... 你的代码 ... ```
请记住, 禁用证书验证会降低安全性 。你应该只在测试环境或你知道自己不需要客户端身份验证的情况下执行此操作。对于生产环境,强烈建议使用适当的证书颁发机构签署的证书,并强制执行客户端证书验证。
标签:python,sockets,ssl,networking From: 78842288