为何Python requests访问指定badssl URL返回200状态码?
问题解释:requests与浏览器对证书问题处理的差异
核心原因:requests默认的SSL验证策略和浏览器不同
1. 针对revoked.badssl.com(证书吊销)
- 浏览器会主动通过CRL(证书吊销列表)或OCSP协议验证证书状态,一旦发现证书被吊销,就会拦截连接并抛出
NET::ERR_CERT_REVOKED错误。 - requests依赖的
urllib3默认不检查证书吊销状态,只要证书本身在有效期内、签名可信,就会正常建立连接,返回200状态码。
2. 针对pinning-test.badssl.com(证书固定失败)
- 主流浏览器内置了证书固定规则(如HPKP或CT机制),当网站返回的证书链不在预设的固定列表中时,会触发安全拦截,抛出
NET::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN错误。 - requests默认不支持证书固定验证,除非手动配置自定义验证逻辑,否则它仅验证证书的合法性,不会检查是否符合固定规则,因此能正常完成请求并返回200。
让requests模拟浏览器的验证逻辑
检测证书吊销
可以通过配置SSL上下文启用OCSP Stapling检查:
import requests from urllib3.contrib.pyopenssl import PyOpenSSLContext context = PyOpenSSLContext() # 启用OCSP stapling验证 context.set_ocsp_client_callback(lambda conn, ocsp_data: True) try: response = requests.get('https://revoked.badssl.com/', verify=context) print(response.status_code) except requests.exceptions.SSLError as e: print(f"SSL错误: {e}")
验证证书固定
手动指定允许的证书指纹,在请求后校验响应证书的指纹是否匹配:
import requests import hashlib def verify_cert_pin(response, expected_sha256): cert = response.raw.connection.sock.getpeercert(True) actual_sha256 = hashlib.sha256(cert).hexdigest() if actual_sha256 != expected_sha256: raise requests.exceptions.SSLError("证书固定验证失败") try: response = requests.get('https://pinning-test.badssl.com/') # 替换为目标网站的合法证书SHA256指纹 verify_cert_pin(response, "合法证书的SHA256指纹") print(response.status_code) except requests.exceptions.SSLError as e: print(f"SSL错误: {e}")
你的测试代码小问题
注意代码中url='https://revoked.badssl.com/' or 'https://pinning-test.badssl.com/'只会取第一个真值(即revoked.badssl.com),无法同时测试两个URL。要测试两个地址,可改为循环调用:
import requests def check_connection(url): try: r = requests.get(url) r.raise_for_status() print(f"{url}: {r.status_code}") except requests.exceptions.RequestException as err: print(f"{url}: 错误 - {err}") # 遍历测试两个URL for url in ['https://revoked.badssl.com/', 'https://pinning-test.badssl.com/']: check_connection(url)
内容的提问来源于stack exchange,提问作者CoderS
相关产品推荐
相关产品推荐

