文档中心
Python瀹炴垬3鍒嗛挓鏁欎綘鐢ㄤ唬鐮佺敓鎴怱SL璇佷功锛堥檮瀹屾暣绀轰緥锛?txt
时间 : 2025-09-27 16:30:28浏览量 : 2

SSL证书是网络安全的基础设施之一,它就像网站的"身份证",确保用户访问的是真实可信的网站。作为开发者,我们经常需要在开发环境或内部系统中使用SSL证书。本文将手把手教你用Python快速生成自签名SSL证书,并深入解析背后的密码学原理。
一、SSL证书的基本原理
想象一下你要给朋友寄一封机密信件。SSL/TLS协议就像:
1. 一个防篡改信封(加密)
2. 一份带印章的授权书(证书验证)
3. 只有收件人知道的解码手册(密钥交换)
常见的证书类型包括:
- DV证书(域名验证):就像简易名片
- OV证书(组织验证):类似带公章的工作证
- EV证书(扩展验证):好比需要面签的护照
二、Python生成证书的4种方法
方法1:使用cryptography库(推荐)
```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 = 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, "My Company"),
x509.NameAttribute(NameOID.COMMON_NAME, "mysite.com"),
])
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.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())
保存证书和私钥
with open("certificate.pem", "wb") as f:
f.write(cert.public_bytes(serialization.Encoding.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()
))
```
方法2:使用OpenSSL命令行封装
import subprocess
def generate_cert(domain="localhost", days=365):
subprocess.run([
"openssl", "req", "-x509", "-newkey", "rsa:4096",
"-keyout", "key.pem", "-out", "cert.pem",
"-days", str(days), "-nodes",
"-subj", f"/CN={domain}"
], check=True)
generate_cert()
方法3:使用pyOpenSSL库
from OpenSSL import crypto
key = crypto.PKey()
key.generate_key(crypto.TYPE_RSA, 2048)
cert = crypto.X509()
cert.get_subject().CN = "localhost"
cert.set_serial_number(1000)
cert.gmtime_adj_notBefore(0)
cert.gmtime_adj_notAfter(365*24*60*60)
cert.set_issuer(cert.get_subject())
cert.set_pubkey(key)
cert.sign(key, 'sha256')
open("certificate.crt", "wb").write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
open("private.key", "wb").write(crypto.dump_privatekey(crypto.FILETYPE_PEM, key))
方法4:使用M2Crypto库
from M2Crypto import X509, RSA, EVP
pk = RSA.gen_key(2048, 65537)
cert = X509.X509()
cert.set_version(2)
cert.set_serial_number(1)
name = X509.X509_Name()
name.CN = "localhost"
name.O = "My Org"
name.OU = "My Unit"
name.C = "CN"
cert.set_subject(name)
cert.set_issuer(name)
pubkey = EVP.PKey()
pubkey.assign_rsa(pk)
cert.set_pubkey(pubkey)
import time
now = int(time.time())
now_str = time.strftime("%Y%m%d%H%M%SZ", time.gmtime(now))
expire_str = time.strftime("%Y%m%d%H%M%SZ", time.gmtime(now + 365*24*60*60))
from M2Crypto import ASN1
now_asn1 = ASN1.ASN1_UTCTIME()
now_asn1.set_string(now_str)
expire_asn1 = ASN1.ASN1_UTCTIME()
expire_asn1.set_string(expire_str)
cert.set_not_before(now_asn1)
cert.set_not_after(expire_asn1)
cert.sign(pubkey, 'sha256')
open("my.crt","w").write(cert.as_pem())
open("my.key","w").write(pk.as_pem(None))
三、生产环境注意事项
虽然自签名证书适合开发和测试,但在生产环境中需要注意:
1. 浏览器警告问题:自签名证书会被标记为"不安全"
- Chrome会显示红色警告页
- Firefox会提示安全风险
2. 有效期管理:
```python
自动检查过期时间示例
from cryptography import x509
with open("certificate.pem", "rb") as f:
cert_data = f.read()
cert = x509.load_pem_x509_certificate(cert_data)
if cert.not_valid_after < datetime.datetime.now():
print("?? 证书已过期!")
```
3. 密钥安全存储:
AES加密私钥示例
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
password = b"strong_password"
salt = os.urandom(16)
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=100000,
)
key_for_storage(private_key, password="password")
四、进阶技巧:CA链式签发
如果需要模拟更真实的CA签发过程:
CA根证书生成示例(简化版)
ca_key = rsa.generate_private_key(public_exponent=65537, key_size=4096)
ca_cert_builder.subject_name(subject)\...
ca_cert_builder.add_extensions([
CA基础约束扩展非常重要!
BasicConstraints(ca=True, path_length=None),
KeyUsage(...),
ca_cert_builder.sign(...)
然后用CA签发终端实体证书:
builder.add_extensions([
AuthorityKeyIdentifier.from_issuer_subject_key_id(...),
builder.sign(private_key=ca_key,...)
五、常见问题解答
Q:为什么我的Python服务使用自签名证书报错?
A:常见原因有:
- SAN扩展缺失(现代浏览器要求)→添加`SubjectAlternativeName`
- SHA-1签名算法不安全→改用SHA-256/384
- RSA密钥长度不足→至少2048位
Q:如何让Python请求忽略SSL验证?
A:(仅限测试环境)
```python
import requests
requests.get('https://example.com', verify=False)
或者创建自定义适配器:
session.mount('https://', SSLAdapter())
Q:如何查看生成的证书详情?
A:使用OpenSSL命令:
openssl x509 -in certificate.pem -text -noout
或Python解析:
print(f"颁发给: {cert.subject.rfc4514_string()}")
print(f"有效期至: {str(cert.not_valid_after)}")
print(f"指纹: {binascii.b2a_base64(cert.fingerprint(...))}")
掌握这些技能后,你就能在开发中灵活应对各种HTTPS需求了!记得生产环境还是要使用受信任CA签发的正式证书哦。
TAG:python 生成 ssl证书,python ssl认证,python ssl certificate,python项目的ssl证书怎么配,pythonssl证书验证错误,python获取ssl证书信息