You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Windows证书存储获取证书字节流直接用于requests请求?

问题

我有一个接收证书签名请求的API,目前用以下方式调用:

response = requests.post(some_url, data=some_data, cert=path_to_cert)

出于安全考虑,我不能把Windows证书存储里的证书下载到本地,必须从内存中发送请求。

有没有支持cert参数接收字符串/字节的库或requests适配器?

我尝试写了下面的代码,但卡在了把字符串/字节传入请求的步骤:

cert_name = "NAME CERT IN CERT STORE"


def export_cert_to_pem(cert, pem_path)->str:
    pem = cert.get_pem()

    return pem

def find_cert_in_trusted_roots(cert_name:str):
    for storename in ("CA", "ROOT"):
        with wincertstore.CertSystemStore(storename) as store:
            for cert in store.itercerts(usage=wincertstore.SERVER_AUTH):
                if cert.get_name().lower() == cert_name.lower():
                    export_cert_to_pem(cert, cert_name + ".pem")

                    # export_cert_to_pem(cert, pem_path)
                    return 1

    return 0


cert = find_cert_in_trusted_roots(cert_name)

# 此处无法运行,cert参数必须传入路径

response = requests.post(some_url, data=your_data, cert=cert)
解决方案

标准requests库的cert参数仅支持文件路径字符串或证书/密钥路径元组,不直接支持内存中的字节/字符串。但可以通过自定义SSL适配器实现从内存加载证书。

方法:结合ssl.SSLContext与自定义requests适配器

先修改证书查找逻辑,同时获取证书和对应私钥的PEM字节数据(客户端证书需要证书+私钥配对):

import wincertstore
import ssl
import requests
from requests.adapters import HTTPAdapter

def find_cert_and_key(cert_name: str):
    # 私钥通常存放在MY存储区,需遍历相关存储
    for storename in ("MY", "CA", "ROOT"):
        with wincertstore.CertSystemStore(storename) as store:
            for cert in store.itercerts(usage=wincertstore.SERVER_AUTH):
                if cert.get_name().lower() == cert_name.lower():
                    # 获取证书PEM字节
                    cert_pem = cert.get_pem()
                    # 获取对应私钥PEM字节(需确保证书关联私钥且当前用户有权限访问)
                    key_pem = cert.get_private_key().get_pem()
                    return cert_pem, key_pem
    return None, None

# 从证书存储获取内存中的证书和私钥
cert_pem, key_pem = find_cert_and_key("NAME CERT IN CERT STORE")

if cert_pem and key_pem:
    # 创建SSL上下文并加载内存中的证书与私钥
    ssl_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
    ssl_context.load_cert_chain(
        certfile=None,
        cert_data=cert_pem,
        keyfile=None,
        key_data=key_pem
    )

    # 自定义适配器,将SSL上下文注入请求池
    class MemoryCertAdapter(HTTPAdapter):
        def init_poolmanager(self, *args, **kwargs):
            kwargs["ssl_context"] = ssl_context
            return super().init_poolmanager(*args, **kwargs)

    # 初始化Session并挂载适配器
    session = requests.Session()
    session.mount("https://", MemoryCertAdapter())

    # 发送请求,无需传入cert参数
    response = session.post(some_url, data=your_data)
else:
    print("未找到目标证书或对应的私钥")

注意事项

  • 证书对应的私钥通常存放在Windows的MY存储区,需确保当前用户有权限访问该私钥。
  • 如果私钥带有密码,需要额外处理解密逻辑,但通过wincertstore获取的私钥一般已处于解密状态。

内容的提问来源于stack exchange,提问作者NonniSnon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 09:13:22