文档中心
PythonSSL鏁板瓧璇佷功璇﹁В浠庡師鐞嗗埌瀹炴垬搴旂敤
时间 : 2025-09-27 16:30:16浏览量 : 4
什么是SSL数字证书?

想象一下你要给朋友寄一封重要的信,SSL数字证书就像是信封上的火漆印章,确保信件在传输过程中不被偷看或篡改。在互联网世界里,SSL(Secure Sockets Layer)数字证书就是网站的身份证明和安全通信的保障。
当你在浏览器地址栏看到那个小锁图标时,就表示你正在通过SSL/TLS加密通道与网站通信。Python作为广泛使用的编程语言,也提供了完善的SSL支持模块。
SSL证书的核心组成
一个标准的SSL证书包含三个关键部分:
1. 公钥:就像公开的电话号码,任何人都可以获取并使用它来加密数据
2. 私钥:就像你的私人密码,必须严格保密,用于解密数据
3. CA签名:由受信任的证书颁发机构(CA)提供的"担保",证明这个公钥确实属于声称的拥有者
举个例子:假设你要登录网上银行。银行服务器会发送它的SSL证书给你的浏览器。浏览器会检查:
- 这个证书是否由可信CA签发(比如VeriSign、Let's Encrypt)
- 证书中的域名是否与你访问的网站一致
- 证书是否在有效期内
Python中的SSL模块基础用法
Python内置的`ssl`模块让我们可以轻松处理SSL连接。下面是一个最简单的HTTPS请求示例:
```python
import ssl
import urllib.request
context = ssl.create_default_context()
response = urllib.request.urlopen("https://example.com", context=context)
print(response.read())
```
这段代码创建了一个默认的SSL上下文,然后用它安全地获取网页内容。`create_default_context()`会自动加载系统信任的根证书。
常见问题与解决方案
1. 自签名证书问题
很多内部系统使用自签名证书(自己充当CA签发的证书),Python默认不信任这类证书:
错误示例 - 会抛出ssl.SSLError
response = urllib.request.urlopen("https://internal-server")
解决方案有三种:
方案A:关闭验证(不推荐)
context = ssl._create_unverified_context()
方案B:添加自定义CA
context = ssl.create_default_context(cafile="my_custom_ca.pem")
方案C:添加单个证书信任
context.load_verify_locations(cafile="server_cert.pem")
2. 主机名验证失败
有时会遇到"hostname doesn't match"错误:
server_cert.pem是发给foo.example.com的,但我们访问的是bar.example.com
response = urllib.request.urlopen("https://bar.example.com", context=context)
解决方案是禁用主机名检查(仅限测试环境):
context.check_hostname = False
3. TLS版本过时问题
老系统可能只支持TLS1.0/1.1等不安全协议:
强制使用现代安全协议 (Python 3.7+)
context.minimum_version = ssl.TLSVersion.TLSv1_2
Python生成自签名证书实战
开发测试时经常需要自签名证书。下面用Python生成一个:
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
import datetime
生成私钥
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
创建自签名证书的主体信息(Subject)
subject = 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, "My Company"),
x509.NameAttribute(NameOID.COMMON_NAME, "mysite.example.com"),
])
设置有效期(通常1年)
cert = x509.CertificateBuilder().subject_name(
subject).issuer_name(
subject).public_key(
private_key.public_key()
).serial_number(
x509.random_serial_number()
).not_valid_before(
datetime.datetime.now(datetime.timezone.utc)
).not_valid_after(
datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=365)
).add_extension(
x509.SubjectAlternativeName([x509.DNSName("localhost")]),
critical=False,
).sign(private_key, hashes.SHA256())
保存私钥和证书到文件(PEM格式)
with open("private_key.pem", "wb") as f:
f.write(private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
))
with open("certificate.pem", "wb") as f:
f.write(cert.public_bytes(serialization.Encoding.PEM))
Flask/Django HTTPS服务配置示例
有了私钥和证书后,我们可以配置Web服务使用HTTPS:
Flask配置示例:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello HTTPS World!"
if __name__ == "__main__":
app.run(ssl_context=('certificate.pem', 'private_key.pem'))
Django配置示例:
在settings.py中添加:
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
Python检查远程服务器SSL信息
我们可以用Python编写工具检查远程服务器的SSL配置情况:
import socket
import ssl
from pprint import pprint
def check_ssl(hostname, port=443):
context = ssl.create_default_context()
with socket.create_connection((hostname, port)) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
cert_info = ssock.getpeercert()
cipher_info = ssock.cipher()
print(f"\n=== {hostname} SSL信息 ===")
print("\n[版本信息]")
print(f"协议版本: {ssock.version()}")
print("\n[加密套件]")
print(f"正在使用的加密算法: {cipher_info[0]}")
print("\n[有效期]")
pprint(cert_info['notBefore'])
pprint(cert_info['notAfter'])
print("\n[主题信息]")
for field in cert_info['subject']:
for k,v in field:
print(f"{k}: {v}")
check_ssl("www.baidu.com")
check_ssl("github.com")
这个脚本可以输出目标网站的:
- SSL/TLS协议版本(TLS1.2/1.3等)
- 正在使用的加密算法套件(AES256-GCM-SHA384等)
- 证书的有效期和主体信息(公司名称、域名等)
Python处理客户端认证(mTLS)
在一些高安全要求的场景中,服务器也会验证客户端的身份——这就是双向TLS认证(mTLS)。比如银行API接口通常要求客户端提供自己的数字证书。
服务端代码示例:
```python
HOST, PORT = '0.0.0.0', 8443
SSL上下文配置 - require client cert!
context_server = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context_server.load_cert_chain('server.crt', 'server.key')
context_server.load_verify_locations('ca.crt')
context_server.verify_mode = ssl.CERT_REQUIRED
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.bind((HOST,PORT))
sock.listen()
with context_server.wrap_socket(sock, server_side=True) as ssock:
conn,_addr_client=ssock.accept()
data_client=conn.read()
conn.write(b"Hello mTLS client!")
conn.close()
客户端代码示例:
import socket
import ssl
HOST,PORT='localhost',8443
Client context with cert chain
context_client=ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
context_client.load_cert_chain('client.crt','client.key')
context_client.load_verify_locations('ca.crt')
with socket.socket(socket.AF_INET,socket.SOCK_STREAM)as sock:
with context_client.wrap_socket(sock,
server_hostname='myserver.local')as ssock:
ssock.connect((HOST,PORT))
ssock.send(b"Hello mTLS world!")
response_data=str(ssock.read(),'utf-8')
print(f"Server response:{response_data}")
这种mTLS模式确保了双方都经过严格身份验证后才能建立连接。
Python中常见的SSLError及解决思路
在使用Python进行HTTPS通信时可能会遇到各种SSLError错误码:
| 错误码 | 常见原因 | 解决方案建议 |
||--||
| CERTIFICATE VERIFY FAILED | CA根不受信任/过期/吊销 | `create_unverified_context()`临时绕过或安装正确CA |
| UNKNOWN CA | CA不在系统信任库中 | `load verify locations()`加载自定义CA |
| HOSTNAME MISMATCH | CN/SAN不匹配实际域名 | `check hostname=False`或修正DNS |
| SSLV3 ALERT HANDSHAKE FAILURE | TLS版本不兼容 | `minimum version=TLSv1\_2`强制升级 |
| DH KEY TOO SMALL | DH参数太弱(<2048bit) | `OP SINGLE DH USE`或更新密钥 |
例如处理过时的金融系统接口可能需要特殊配置:
``` python
legacy ctx=ssl SSLContext(protocol PROTOCOL TLS CLIENT)
旧版协议兼容模式
legacy ctx set ciphers('DES CBC3 SHA:AES128 SHA256')
指定老旧算法套件
legacy ctx verify mode=CERT OPTIONAL
放宽验证要求
try requests get(url=https legacybank com api balance verify='/path/to/legacy ca pem')
except SSLError as e: logger warning(f'Handshake failed:{e} retrying...')
这种场景下需要在安全性和兼容性之间做出权衡决策。
通过以上内容我们可以看到,Python提供了强大而灵活的SSL/TLS支持能力。无论是开发安全的客户端程序、构建HTTPS服务还是进行安全测试分析都能找到合适的工具方法。理解这些原理和技术细节将帮助开发者构建更加安全的网络应用系统。
TAG:python ssl 数字证书,python项目的ssl证书怎么配,python ssl认证,python ssl模块详解