ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

requests 测试证书实战:用 OpenSSL 自制一张「已过期」TLS 证书来验证 SSL 校验行为

requests 测试证书实战:用 OpenSSL 自制一张「已过期」TLS 证书来验证 SSL 校验行为 requests 测试证书实战用 OpenSSL 自制一张「已过期」TLS 证书来验证 SSL 校验行为【免费下载链接】requestsA simple, yet elegant, HTTP library.项目地址: https://gitcode.com/GitHub_Trending/re/requests在 requests 的测试体系中有一组专门用来复现服务器证书已过期场景的 TLS 证书tests/certs/expired/。它由一个完全有效的 CA 和一张有效期为 0 天的服务器证书组成让测试代码无需等待真实时间流逝就能稳定地触发客户端的证书过期错误。本文基于 过期证书说明文档 及其配套构建脚本完整拆解这套证书目录的结构、make再生流程、OpenSSL 配置细节以及 requests 测试用例如何利用它断言SSLError帮你掌握自制可控证书用于 TLS 行为测试的通用方法论。目录结构一个有效 CA 一张过期服务器证书根据 tests/certs/expired/README.md 的说明该目录的设计意图非常明确This has a valid certificate authority incaand an invalid server certificate inserver.也就是两个子目录各自承担一个角色子目录角色状态产物tests/certs/expired/ca/自签名根 CA有效20 年ca-private.key、ca.crt及符号链接cacert.pem、序列号文件ca.srltests/certs/expired/server/由该 CA 签发的服务器证书已过期有效期 0 天server.key、server.csr、server.pem含证书 CA 证书链它也是整个 tests/certs/ 测试证书集合的一部分与 有效服务器证书valid和 mTLS 客户端证书mtls互为对照组——过期版用来验证CA 信任没问题、唯独证书过期这一单一变量下的行为避免与其他 TLS 故障混在一起。一键再生make cleanmake allREADME 给出的再生方式只有两条命令make clean make all这两条命令的实际行为由顶层 Makefile 定义它本身不含任何 OpenSSL 调用只是分发到两个子目录.PHONY: all clean ca server ca: make -C $ all server: make -C $ all all: ca server clean: make -C ca clean make -C server clean注意目标依赖顺序all先构建ca再构建server因为服务器证书必须以 CA 的ca.crt和ca-private.key作为签发输入clean则把两个子目录的生成物全部清掉cacert.pem、ca.crt、ca-private.key、*.csr、server.*。整个构建只依赖 OpenSSL 和 Make没有 Python 参与因此在任何干净的机器上都能复现。CA 证书20 年有效期的自签名根ca/Makefile 完整流程root_files ca-private.key ca-private.key: openssl genrsa -out ca-private.key 2048 all: ca-private.key openssl req -x509 -sha256 -days 7300 -key ca-private.key -out ca.crt -config ca.cnf ln -s ca.crt cacert.pem clean: rm -f cacert.pem ca.crt ca-private.key *.csr要点openssl genrsa -out ca-private.key 2048生成 2048 位 RSA 私钥作为后续所有签名的根openssl req -x509 ... -days 7300直接签发一张自签名 CA 证书7300天 ≈ 20 年保证 CA 在测试期间永远有效——这正是CA 有效、叶子证书过期对照实验成立的前提ln -s ca.crt cacert.pem建一个符号链接兼容习惯用cacert.pem命名的客户端/服务器代码。CA 的身份与扩展配置在 ca.cnf 中[req] default_bits 2048 prompt no default_md sha256 encrypt_key no distinguished_name dn x509_extensions v3_ca [dn] C US # country code O Python Software Foundation # organization OU python-requests # organization unit/department CN Self-Signed Root CA # common name / your cert name [v3_ca] basicConstraints critical, CA:true keyUsage critical, cRLSign, digitalSignature, keyCertSignprompt no表示完全按[dn]段读取不会交互式询问[v3_ca]段中的basicConstraints critical, CA:true和keyUsage critical, cRLSign, digitalSignature, keyCertSign是 X.509 v3 里这张证书只能当 CA 用的标准声明缺少它们客户端校验链时可能直接拒绝。服务器证书-days 0是过期实验的核心技巧server/Makefile 展示了完整的私钥 → CSR → 证书三步链server.key: openssl genrsa -out $ 2048 server.csr: server.key openssl req -key $ -new -out $ -config cert.cnf server.pem: server.csr openssl x509 -req -CA ../ca/ca.crt -CAkey ../ca/ca-private.key -in server.csr -outform PEM -out server.pem -days 0 -CAcreateserial openssl x509 -in ../ca/ca.crt -outform PEM $ all: server.pem clean: rm -f server.*逐条解读openssl req -key $ -new -out $ -config cert.cnf基于服务器私钥生成 CSR证书签名请求主体信息来自配置而非交互输入openssl x509 -req -CA ../ca/ca.crt -CAkey ../ca/ca-private.key ... -days 0用 CA 的证书和私钥签发叶子证书-days 0是整套实验的题眼——签发完成的那一刻证书就已过期notAfter 早于当前时间无需等真实时间过去-CAcreateserial顺便创建 CA 序列号文件即仓库中的ca.srlopenssl x509 -in ../ca/ca.crt -outform PEM $把 CA 证书追加进server.pem使这份文件成为一个自带完整证书链的 bundle服务器证书在前、CA 证书在后这样测试用的 TLS 服务器只需指定一个文件即可通过ssl模块加载完整链。另外 Makefile 用到了$第一个前置条件这类 GNU Make 变量构建顺序由server.pem: server.csr、server.csr: server.key逐级推导依赖关系清晰。服务器身份localhost / 127.0.0.1 / ::1 全打满server/cert.cnf 定义了 CSR 的主体与关键扩展[req] req_extensions v3_req distinguished_name req_distinguished_name promptno [req_distinguished_name] C US ST DE O Python Software Foundation OU python-requests CN localhost [v3_req] # Extensions to add to a certificate request basicConstraints CA:FALSE keyUsage digitalSignature, keyEncipherment extendedKeyUsage serverAuth subjectAltName alt_names [alt_names] DNS.1 *.localhost DNS.1 localhost IP.1 127.0.0.1 IP.2 ::1[v3_req]段是关键basicConstraints CA:FALSEkeyUsage digitalSignature, keyEncipherment声明这是一张终端实体服务器证书extendedKeyUsage serverAuth限定用途为 TLS 服务端认证subjectAltName覆盖localhost、*.localhost、127.0.0.1和 IPv6 回环::1——现代客户端早已不校验 CN 而校验 SAN把本地回环地址全部写进 SAN才能保证无论测试服务器绑定127.0.0.1还是localhost主机名校验这一变量不会污染过期这个唯一变量。测试用例如何使用这套过期证书这套证书的消费方在 tests/test_requests.py。典型用例test_different_connection_pool_for_tls_settings_verify_bundle_expired_cert约 L2959-L2990展示了三层断言server TLSServer( handlerresponse_handler, wait_to_close_eventclose_server, requests_to_handle3, cert_chaintests/certs/expired/server/server.pem, keyfiletests/certs/expired/server/server.key, ) with server as (host, port): url fhttps://{host}:{port} r1 s.get(url, verifyFalse) assert r1.status_code 200 # Has right trust bundle, but certificate expired with pytest.raises(requests.exceptions.SSLError): s.get(url, verifytests/certs/expired/ca/ca.crt)三个关键点verifyFalse能拿到 200关闭校验时请求本身是通的说明传输层没问题错误只可能出在校验逻辑verifytests/certs/expired/ca/ca.crt抛出requests.exceptions.SSLError客户端把这张过期证书的签发者——那个完全有效的 CA——作为信任根传入信任链每一环都对唯独时间校验失败于是底层ssl抛CERTIFICATE_HAS_EXPIREDrequests 包装成SSLError上抛。这是整组证书设计的直接验证错误不是因为你选错了 CA而是因为证书过期相邻用例如 L2992 起的..._verify_bundle_unexpired_cert换用 tests/certs/valid/ 下的有效证书做正对照L3037 起的 mTLS 用例则把过期服务器证书与 mtls 客户端证书 组合验证双向认证场景下过期同样触发SSLError。这种同一 TLS 服务器 不同verify入参 断言 200 / SSLError的模式正是过期证书目录存在的价值它把一个依赖时间流逝、否则极难在 CI 中稳定复现的边界条件固化成了随仓库分发的静态资产。复用这套方法如何给自己的项目造可控的过期证书把 server/Makefile 的流程抽象出来是一份可以直接照抄的最小配方# 1. 生成 CA长期有效 openssl genrsa -out ca-private.key 2048 openssl req -x509 -sha256 -days 7300 -key ca-private.key -out ca.crt -config ca.cnf # 2. 生成服务器私钥与 CSRCN/SAN 指向你的测试域名或回环地址 openssl genrsa -out server.key 2048 openssl req -key server.key -new -out server.csr -config cert.cnf # 3. 用 CA 签发-days 0 使证书即刻过期再把 CA 追加进 bundle 形成完整链 openssl x509 -req -CA ca.crt -CAkey ca-private.key -in server.csr \ -outform PEM -out server.pem -days 0 -CAcreateserial openssl x509 -in ca.crt -outform PEM server.pem配套ca.cnf/cert.cnf的最小要点与仓库完全一致CA 侧必须写basicConstraints critical, CA:true和含keyCertSign的keyUsage服务器侧必须写extendedKeyUsage serverAuth和覆盖实际测试地址的subjectAltName用prompt no保证构建可重复、无人值守。适用前提与限制该方案依赖系统openssl与 GNU Make用于测试环境完全足够生成的证书 CN 为localhost、组织信息为 Python Software Foundation / python-requests仅用于本地回环测试不应部署到任何真实服务端。若只需要当前已过期的静态证书直接复用仓库里现成的 server.pem 与 ca.crt 即可不必再生成只有需要自定义域名或更长/更短的剩余寿命时才需改动-days参数重新构建。小结tests/certs/expired/ 这套资产的核心思想可以概括为三点单变量控制CA 有效期 7300 天保证信任链恒有效服务器证书-days 0保证即刻过期过期成为唯一被测试的变量构建即文档make clean make all两条命令可完整再生全部证书三个 Makefile 与两份 openssl 配置就是可执行的说明书测试闭环tests/test_requests.py 中verifyFalse得 200、verify有效CA却抛SSLError的对照断言直接证明了这套证书精确地只制造过期这一种故障。理解并复用这套模式后你可以在自己的 TLS 相关测试中用同样手段稳定复现证书过期、自签名、链不完整等边界条件而不再依赖真实时钟或外部服务。【免费下载链接】requestsA simple, yet elegant, HTTP library.项目地址: https://gitcode.com/GitHub_Trending/re/requests创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表