杰瑞科技汇

Python如何用with语句操作OpenSSL?

  1. 最直接的方式:使用 cryptography
  2. 标准库方式:使用 ssl 模块
  3. 系统级集成:编译 Python 时绑定特定版本的 OpenSSL
  4. 检查和验证 Python 程序使用的 OpenSSL 版本

最直接、最现代的方式:cryptography

对于绝大多数需要直接操作 OpenSSL 功能(如创建密钥、证书、加密/解密数据)的开发者来说,cryptography 库是最佳选择,它是一个高级的密码学库,其底层直接调用 OpenSSL,但提供了比 OpenSSL 原生 C API 更 Pythonic、更安全的接口。

Python如何用with语句操作OpenSSL?-图1
(图片来源网络,侵删)

为什么推荐 cryptography

  • Pythonic API:接口设计符合 Python 的习惯,易于使用。
  • 安全性:它努力避免常见的加密错误(如使用不安全的填充、模式等)。
  • 跨平台:预编译的二进制包在 Windows, macOS, 和 Linux 上都可用,并会自动链接到系统上安装的 OpenSSL。
  • 功能全面:涵盖了现代密码学的方方面面,从非对称加密、哈希到密钥派生。

安装

pip install cryptography

示例:使用 RSA 加密和解密数据

这个例子展示了如何使用 cryptography 库进行非对称加密,这背后就是 OpenSSL 在工作。

from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
# --- 1. 生成 RSA 密钥对 ---
# 私钥用于解密和签名,公钥用于加密和验证签名
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
)
public_key = private_key.public_key()
print("RSA 密钥对已生成。")
# --- 2. 使用公钥加密数据 ---
message = b"这是一条需要保密的敏感信息。"
print(f"原始消息: {message.decode()}")
# 使用 OAEP 填充和 SHA-256 哈希,这是现代且安全的做法
ciphertext = public_key.encrypt(
    message,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)
print(f"加密后的密文: {ciphertext.hex()}")
# --- 3. 使用私钥解密数据 ---
# 在实际应用中,接收方会用自己的私钥来解密
decrypted_message = private_key.decrypt(
    ciphertext,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)
print(f"解密后的消息: {decrypted_message.decode()}")
# --- 4. 序列化和保存密钥 ---
# 将私钥和公钥保存到文件中,以便将来使用
# 保存私钥 (需要设置密码保护)
pem_private_key = private_key.private_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PrivateFormat.PKCS8,
    encryption_algorithm=serialization.BestAvailableEncryption(b'my-secret-password')
)
with open("private_key.pem", "wb") as f:
    f.write(pem_private_key)
print("私钥已保存到 private_key.pem")
# 保存公钥
pem_public_key = public_key.public_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PublicFormat.SubjectPublicKeyInfo
)
with open("public_key.pem", "wb") as f:
    f.write(pem_public_key)
print("公钥已保存到 public_key.pem")

标准库方式:ssl 模块

Python 的标准库 ssl 模块是 with 语句与 OpenSSL 结合最紧密、最常见的应用场景,它主要用于创建安全的网络连接,即 TLS/SSL 加密通道

with 语句在这里的作用是确保网络连接在代码块执行完毕后,无论是否发生异常,都能被正确关闭。

核心概念

  • ssl.wrap_socket(): 包装一个普通的套接字,使其变为安全的套接字。
  • ssl.create_default_context(): 推荐使用此函数创建一个安全的 SSL 上下文,它会自动加载系统的信任根证书,并使用安全的默认设置(如禁用不安全的协议和弱密码套件)。
  • 服务器端 vs. 客户端
    • 服务器端:需要一个证书和对应的私钥来证明自己的身份。
    • 客户端:需要验证服务器的证书是否可信。

示例:创建一个安全的 HTTPS 服务器

这是一个简单的 HTTPS 服务器,它监听端口 4443,并为任何连接提供加密服务。

Python如何用with语句操作OpenSSL?-图2
(图片来源网络,侵删)
import http.server
import ssl
# --- 1. 准备证书和私钥 ---
# 在实际生产环境中,你应该从受信任的证书颁发机构(CA)获取证书。
# 这里我们使用 OpenSSL 命令行工具自签名一个证书用于测试。
# (在终端运行):
# openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365 -nodes
# 这会生成 cert.pem (证书) 和 key.pem (私钥) 文件。
# --- 2. 设置服务器 ---
# 切换到包含 cert.pem 和 key.pem 的目录
# 或者修改下面的路径为你文件的路径
PORT = 4443
Handler = http.server.SimpleHTTPRequestHandler
# 创建一个默认的 SSL 上下文
# load_default_certs=True 会加载系统信任的 CA 证书
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
# 加载服务器证书和私钥
# 请确保 'cert.pem' 和 'key.pem' 文件在同一目录下,或提供完整路径
try:
    context.load_cert_chain(certfile='cert.pem', keyfile='key.pem')
except FileNotFoundError:
    print("错误: 请确保 'cert.pem' 和 'key.pem' 文件存在。")
    print("你可以使用 OpenSSL 生成自签名证书: ")
    print("openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365 -nodes")
    exit()
# --- 3. 启动服务器 ---
# 使用 with 语句,确保服务器套接字在退出时被正确关闭
with http.server.HTTPServer(('', PORT), Handler) as httpd:
    # 使用 SSLContext 包装服务器套接字
    httpd.socket = context.wrap_socket(httpd.socket, server_side=True)
    print(f"服务器启动在 https://localhost:{PORT}")
    print("按 Ctrl+C 停止服务器")
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        print("\n服务器正在关闭...")
        httpd.server_close()
        print("服务器已关闭。")

如何运行这个例子

  1. 将上面的代码保存为 https_server.py
  2. 在终端中,使用 OpenSSL 生成证书和私钥:
    openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365 -nodes

    在生成过程中,它会询问一些信息,你可以直接按回车使用默认值。

  3. 确保生成的 cert.pemkey.pemhttps_server.py 在同一目录下。
  4. 运行 Python 脚本:
    python https_server.py
  5. 打开你的浏览器,访问 https://localhost:4443,你会看到一个浏览器安全警告,因为这是一个自签名证书,点击“高级”并继续访问即可看到当前目录的文件列表。

系统级集成:编译 Python 时绑定特定版本的 OpenSSL

在某些特殊情况下,你可能需要 Python 绑定到一个特定版本的 OpenSSL,而不是系统默认的版本,这通常发生在以下场景:

  • 你需要使用某个特定 OpenSSL 版本的新特性。
  • 你需要修复一个旧版 Python 的 OpenSSL 安全漏洞,但系统无法升级 OpenSSL。
  • 你正在构建一个需要精确控制依赖的 Docker 镜像。

这个过程比较复杂,通常涉及从源代码编译 Python。

基本步骤:

Python如何用with语句操作OpenSSL?-图3
(图片来源网络,侵删)
  1. 下载并编译 OpenSSL:从 OpenSSL 官网下载源码,编译并安装到自定义目录(/usr/local/openssl)。
  2. 下载并编译 Python:从 Python 官网下载源码。
  3. 配置编译选项:在运行 ./configure 时,使用 --with-openssl 参数指向你自定义编译的 OpenSSL 路径。
    ./configure --with-openssl=/path/to/your/custom/openssl
    make
    sudo make install

注意:对于绝大多数开发者来说,这是不必要的,直接使用操作系统包管理器或 pyenv 等工具管理 Python 版本会更简单。


检查 Python 程序使用的 OpenSSL 版本

你可以通过以下几种方式检查你的 Python 解释器正在使用哪个版本的 OpenSSL。

使用 ssl 模块 (最简单)

import ssl
print(ssl.OPENSSL_VERSION)
# 输出示例: OpenSSL 1.1.1k  FIPS 25 Mar 2025

使用 ctypes 模块 (更底层)

这种方法可以获取到 OpenSSL 的版本号信息,而不仅仅是版本字符串。

import ssl
import ctypes
import ctypes.util
# 加载 OpenSSL 的共享库
lib = ctypes.CDLL(ctypes.util.find_library("ssl"))
# 获取版本号函数
# 注意:函数名在不同版本中可能略有不同 (OpenSSL_version vs. OpenSSL_version_num)
# OpenSSL_version_num 更可靠
version_num = lib.OpenSSL_version_num()
major = (version_num >> 28) & 0xF
minor = (version_num >> 20) & 0xFF
fix = (version_num >> 12) & 0xFF
patch = (version_num >> 4) & 0xFF
status = version_num & 0xF
print(f"OpenSSL Version Number: {version_num:#x}")
print(f"Major: {major}, Minor: {minor}, Fix: {fix}, Patch: {patch}, Status: {status}")
# 格式化输出版本号
print(f"Formatted Version: {major}.{minor}.{fix}")
场景 推荐工具 with 和 OpenSSL 的关系
编写安全网络客户端/服务器 ssl (标准库) 核心应用with 语句用于安全地管理加密套接字的整个生命周期。
实现自定义加密/解密逻辑 cryptography (第三方库) 底层依赖cryptography 提供高级 API,其内部调用 OpenSSL 来执行实际的密码学运算。
需要精确控制 OpenSSL 版本 从源码编译 Python 环境配置,在构建 Python 解释器时指定 OpenSSL 的路径,影响整个 Python 环境的行为。
检查 OpenSSL 版本 ssl.OPENSSL_VERSION 信息获取,用于调试和确认运行环境。

对于绝大多数 Python 你只需要记住:

  • 要做 网络通信安全,用 ssl 模块,并用 with 语句管理连接。
  • 要做 底层数据加密,用 cryptography 库,它安全又好用。
分享:
扫描分享到社交APP
上一篇
下一篇