Python SSL与TLS安全连接实现细节
Python SSL与TLS安全连接实现细节
ssl模块提供TLS/SSL协议的Python封装。它基于OpenSSL库,支持客户端和服务器的安全通信。
创建TLS上下文:
import ssl
# 创建客户端上下文
ctx = ssl.create_default_context()
# 自动加载系统CA证书
# 创建服务器上下文
server_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
server_ctx.load_cert_chain(certfile='server.crt', keyfile='server.key')
create_default_context根据用途预设安全选项。ssl.Purpose.SERVER_AUTH用于客户端连接,ssl.Purpose.CLIENT_AUTH用于服务器连接。
自定义上下文选项:
ctx = ssl.create_default_context()
# 设置最低TLS版本
ctx.minimum_version = ssl.TLSVersion.TLSv1_2
# 设置密码套件
ctx.set_ciphers('ECDHE+AESGCM:!aNULL:!MD5')
# 禁用不安全的协议
ctx.options |= ssl.OP_NO_TLSv1
ctx.options |= ssl.OP_NO_TLSv1_1
TLS版本和密码套件的配置直接影响安全性。SSLv2/3已完全废弃。
安全客户端连接:
import socket
import ssl
hostname = 'example.com'
ctx = ssl.create_default_context()
with socket.create_connection((hostname, 443)) as sock:
with ctx.wrap_socket(sock, server_hostname=hostname) as ssock:
print(f"TLS version: {ssock.version()}")
print(f"Cipher: {ssock.cipher()}")
print(f"Certificate: {ssock.getpeercert()}")
ssock.sendall(b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")
data = ssock.read(1024)
wrap_socket将普通socket包装为TLS socket。server_hostname启用SNI和主机名校验。
证书验证细节:
cert = ssock.getpeercert()
if cert:
print(f"Subject: {dict(x[0] for x in cert['subject'])}")
print(f"Issuer: {dict(x[0] for x in cert['issuer'])}")
print(f"Valid from: {cert['notBefore']}")
print(f"Valid to: {cert['notAfter']}")
print(f"Serial: {cert['serialNumber']}")
getpeercert(binary_form=True)返回DER格式的原始证书。配合cryptography库深入解析。
自定义证书验证:
def verify_cert(conn, cert, errno, depth, ok):
if depth == 0: # 叶子证书
if cert.subject.get_attributes_for_oid('2.5.4.3')[0].value != 'example.com':
return False
return ok
ctx = ssl.create_default_context()
ctx.verify_flags = ssl.VERIFY_X509_STRICT
# 通过set_verify回调自定义验证逻辑
服务器端TLS:
import socket
import ssl
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ctx.load_cert_chain('server.crt', 'server.key')
# 要求客户端证书
ctx.verify_mode = ssl.CERT_REQUIRED
ctx.load_verify_locations('ca.crt')
with socket.socket() as sock:
sock.bind(('localhost', 8443))
sock.listen(5)
with ctx.wrap_socket(sock, server_side=True) as ssock:
conn, addr = ssock.accept()
# 处理连接
CERT_REQUIRED要求客户端提供证书。CERT_OPTIONAL接受但不强制。CERT_NONE不验证客户端证书。
内存中的证书加载:
# 从字符串加载证书
cert_pem = b"-----BEGIN CERTIFICATE-----\n..."
key_pem = b"-----BEGIN PRIVATE KEY-----\n..."
ctx.load_cert_chain(cadata=cert_pem, keyfile=key_pem)
# 从内存加载CA证书
ctx.load_verify_locations(cadata=cert_pem)
SSL上下文对象线程安全,但在多线程中应避免同时修改。
会话复用:
ctx.set_session_id(b"MyApplication")
# 创建会话对象
session = ssock.session
# 在新连接上复用会话
new_ssock.session = session
会话复用减少TLS握手次数,提升性能。
ALPN协议协商:
ctx.set_alpn_protocols(['h2', 'http/1.1'])
# 服务器端设置
# ctx.set_alpn_protocols(['h2', 'http/1.1'])
alpn = ssock.selected_alpn_protocol()
print(f"Negotiated: {alpn}") # 'h2'或'http/1.1'
ALPN(应用层协议协商)让TLS握手阶段商定上层协议。
SSL/TLS的最佳实践:
ctx = ssl.create_default_context()
# 禁用压缩(防止CRIME攻击)
ctx.options |= ssl.OP_NO_COMPRESSION
# 启用安全重协商
ctx.options |= ssl.OP_NO_RENEGOTIATION
# 设置DH参数(前向安全性)
# ctx.load_dh_params('dhparam.pem')
# 设置会话缓存
ctx.session_stats()
OP_NO_COMPRESSION防止CRIME攻击。OP_NO_RENEGOTIATION防止重新协商。DH参数提供完美前向安全性。
