- 使用 Python 的
cryptography库:这是最推荐、最现代、最安全的方式,你可以用它来生成自签名证书、创建证书签名请求、验证证书等。cryptography库是对 OpenSSL 功能的高级封装,提供了更友好的 Pythonic API。 - 使用
openssl命令行工具:通过 Python 的subprocess模块来调用系统自带的openssl命令,这种方式比较直接,但需要你熟悉 OpenSSL 命令行参数,并且处理起来稍显繁琐。
下面我将重点介绍第一种方式(cryptography),因为它更符合 Python 开发的习惯,并会简要提及第二种方式。

使用 Python cryptography 库
你需要安装这个库:
pip install cryptography
生成自签名证书 (Self-Signed Certificate)
自签名证书通常用于本地开发、测试环境或内部服务,因为它不受受信任的证书颁发机构(CA)的信任。
目标:创建一个包含私钥和公钥的 PEM 格式文件 (server.key 和 server.crt)。
代码示例:

from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.backends import default_backend
from datetime import datetime, timedelta
# 1. 生成私钥
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)
# 2. 创建证书构建器
builder = x509.CertificateBuilder()
# 3. 设置证书的各种属性
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 Dev Company"),
x509.NameAttribute(NameOID.COMMON_NAME, "localhost"),
])
builder = builder.subject_name(subject) \
.issuer_name(issuer) \
.public_key(private_key.public_key()) \
.serial_number(x509.random_serial_number()) \
.not_valid_before(datetime.utcnow()) \
.not_valid_after(datetime.utcnow() + timedelta(days=365)) # 证书有效期1年
# 4. 添加扩展(非常重要,用于指定证书用途)
builder = builder.add_extension(
x509.BasicConstraints(ca=False, path_length=None), critical=True,
)
builder = builder.add_extension(
x509.KeyUsage(
digital_signature=True,
content_commitment=False,
key_encipherment=True,
data_encipherment=False,
key_agreement=False,
key_cert_sign=False,
crl_sign=False,
encipher_only=False,
decipher_only=False
),
critical=True,
)
builder = builder.add_extension(
x509.ExtendedKeyUsage([x509.oid.ExtendedKeyUsageOID.SERVER_AUTH]),
critical=False,
)
# 5. 签名证书(用自己的私钥签名,因为是自签名)
certificate = builder.sign(
private_key=private_key, algorithm=hashes.SHA256(), backend=default_backend()
)
# 6. 将私钥和证书保存到文件
# 保存私钥
with open("server.key", "wb") as f:
f.write(private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption()
))
# 保存证书
with open("server.crt", "wb") as f:
f.write(certificate.public_bytes(serialization.Encoding.PEM))
print("自签名证书生成成功: server.key 和 server.crt")
创建证书签名请求 (CSR)
CSR 是向证书颁发机构(CA)申请证书时提交的请求,包含了你的公钥和一些身份信息。
目标:创建一个 server.csr 文件。
代码示例:
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.backends import default_backend
# 1. 生成私钥(这个私钥将用于后续接收CA签发的证书)
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)
# 2. 创建CSR构建器
builder = x509.CertificateSigningRequestBuilder()
# 3. 设置CSR的主体信息
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 Prod Company"),
x509.NameAttribute(NameOID.COMMON_NAME, "my-website.com"),
])
builder = builder.subject_name(subject)
# 4. 添加可选的扩展
builder = builder.add_extension(
x509.BasicConstraints(ca=False, path_length=None), critical=True,
)
# 5. 使用私钥对CSR进行签名
csr = builder.sign(
private_key=private_key, algorithm=hashes.SHA256(), backend=default_backend()
)
# 6. 将CSR保存到文件
with open("server.csr", "wb") as f:
f.write(csr.public_bytes(serialization.Encoding.PEM))
# 同时也保存好私钥,因为你后续需要用它来解密或签名
with open("server.key", "wb") as f:
f.write(private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption()
))
print("CSR生成成功: server.csr 和 server.key")
使用CA签名CSR(颁发证书)
如果你有一个自己的CA(证书颁发机构),你可以用它来签发你之前生成的CSR,这模拟了真实世界的证书申请流程。

前提:你需要一个CA的私钥和证书,我们可以用上面的方法先生成一个CA。
代码示例:
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.backends import default_backend
from datetime import datetime, timedelta
# --- 假设这是你的CA的私钥和证书 ---
# 在实际应用中,这些文件应该被安全地存储
with open("ca.key", "rb") as f:
ca_private_key = serialization.load_pem_private_key(
f.read(),
password=None, # 如果私钥有密码,在这里提供
backend=default_backend()
)
with open("ca.crt", "rb") as f:
ca_cert = x509.load_pem_x509_certificate(f.read(), default_backend())
# --- 加载你之前生成的CSR ---
with open("server.csr", "rb") as f:
csr = x509.load_pem_x509_csr(f.read(), default_backend())
# --- 使用CA来签发证书 ---
builder = x509.CertificateBuilder()
builder = builder.subject_name(csr.subject) \
.issuer_name(ca_cert.subject) \
.public_key(csr.public_key()) \
.serial_number(x509.random_serial_number()) \
.not_valid_before(datetime.utcnow()) \
.not_valid_after(datetime.utcnow() + timedelta(days=365)) # 1年有效期
# 添加与CSR中相同的扩展
for extension in csr.extensions:
builder = builder.add_extension(extension.value, critical=extension.critical)
# 使用CA的私钥进行签名
server_cert = builder.sign(
private_key=ca_private_key, algorithm=hashes.SHA256(), backend=default_backend()
)
# --- 保存签发后的服务器证书 ---
with open("server_signed.crt", "wb") as f:
f.write(server_cert.public_bytes(serialization.Encoding.PEM))
print("CA证书签发成功: server_signed.crt")
使用 openssl 命令行工具
如果你更喜欢直接使用 OpenSSL 命令,可以通过 Python 的 subprocess 模块来执行。
生成自签名证书
import subprocess
# 生成私钥
subprocess.run(
["openssl", "genrsa", "-out", "server_cli.key", "2048"],
check=True
)
# 生成自签名证书
subprocess.run([
"openssl", "req", "-new", "-x509", "-key", "server_cli.key",
"-out", "server_cli.crt", "-days", "365",
"-subj", "/C=CN/ST=Beijing/L=Beijing/O=My Dev Company/CN=localhost"
], check=True)
print("OpenSSL命令生成自签名证书成功: server_cli.key 和 server_cli.crt")
创建 CSR
import subprocess
# 生成私钥
subprocess.run(
["openssl", "genrsa", "-out", "server_cli.key", "2048"],
check=True
)
# 创建CSR
subprocess.run([
"openssl", "req", "-new", "-key", "server_cli.key",
"-out", "server_cli.csr",
"-subj", "/C=CN/ST=Beijing/L=Beijing/O=My Prod Company/CN=my-website.com"
], check=True)
print("OpenSSL命令生成CSR成功: server_cli.csr 和 server_cli.key")
Python 应用中使用证书
生成了证书后,最常见的是在 Web 服务器(如 Flask, FastAPI, Django)或 gRPC 服务器中启用 HTTPS。
示例:在 Flask 中使用自签名证书
from flask import Flask
import ssl
app = Flask(__name__)
# 添加一个路由
@app.route('/')
def hello():
return "Hello, Secure World!"
if __name__ == '__main__':
# 加载我们之前生成的证书和私钥
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain('server.crt', 'server.key')
# 启动应用,并启用 SSL
# 注意:浏览器会警告这是一个不安全的连接,因为证书是自签名的
app.run(host='0.0.0.0', port=443, ssl_context=context)
总结与建议
| 特性 | cryptography 库 |
openssl 命令行 |
|---|---|---|
| 易用性 | 高,Pythonic API,逻辑清晰。 | 低,需要记忆命令和参数,处理文本输出。 |
| 集成度 | 高,无缝集成到 Python 应用逻辑中。 | 中等,通过 subprocess 调用,有进程间通信开销。 |
| 灵活性 | 高,可以精细地控制证书的每一个字节和扩展。 | 高,OpenSSL 功能极其强大,命令行参数也很多。 |
| 安全性 | 高,避免了对 shell 命令的依赖,减少了注入风险。 | 中等,需要小心处理命令参数,防止命令注入。 |
| 推荐场景 | Python 应用开发、自动化脚本、需要证书逻辑集成。 | 一次性任务、快速测试、熟悉 OpenSSL 的用户。 |
强烈建议:在 Python 项目中,优先使用 cryptography 库来处理所有与证书相关的任务,它更安全、更易于维护,并且能更好地融入你的 Python 代码库。
