3. requests 库安全特性:HTTPS 支持、证书验证机制、安全头处理
在供应链安全与权限审计场景中,requests 库的传输层安全特性是镜像源通信的第一道防线。本章聚焦 HTTPS 协议支持、证书链验证机制以及安全响应头处理,帮助 DevSecOps 工程师在自动化巡检中避免中间人攻击、证书劫持与敏感信息泄露。
3.1 HTTPS 支持与协议协商
requests 库默认对 https:// 开头的 URL 启用 TLS 加密传输,底层依赖 urllib3 与 ssl 模块。在镜像源巡检场景中,必须确认服务端支持 TLS 1.2 及以上协议,并禁用已废弃的 SSLv2/v3 与 TLS 1.0/1.1。
| 协议版本 | requests 默认支持 | 安全水位要求 | 审计建议 |
|---|---|---|---|
| SSLv2 / SSLv3 | 否(已移除) | 禁止 | 直接阻断 |
| TLS 1.0 / 1.1 | 是(urllib3 兼容) | 禁止 | 通过 ssl_context 限制 |
| TLS 1.2 | 是 | 最低要求 | 强制启用 |
| TLS 1.3 | 是(Python 3.7+) | 推荐 | 优先协商 |
巡检水位指标: 在镜像源证书审计脚本中,应使用
requests.get(..., timeout=10) 并捕获 requests.exceptions.SSLError,同时记录服务端 TLS 版本号,低于 1.2 的节点标记为高危。
import requests
from requests.packages.urllib3.util.ssl_ import create_urllib3_context
# 强制限制 TLS 版本为 1.2+
ctx = create_urllib3_context()
ctx.minimum_version = ssl.TLSVersion.TLSv1_2
session = requests.Session()
session.adapters['https://'].init_poolmanager(ssl_context=ctx)
try:
resp = session.get('https://mirror.example.com/pypi/simple/', timeout=10)
print(f"TLS 协商成功,状态码: {resp.status_code}")
except requests.exceptions.SSLError as e:
print(f"TLS 版本不满足安全水位: {e}")
3.2 证书验证机制
requests 库默认启用证书验证(verify=True),通过系统 CA 包或自定义 CA 文件校验服务端证书链。在供应链镜像源场景中,证书验证失败必须阻断请求,避免中间人攻击。
安全红线: 生产环境禁止设置
verify=False。仅在隔离测试网络中使用自定义 CA 时,可通过 verify='/path/to/ca-bundle.crt' 指定信任锚点。
证书验证的核心流程包括:
- 证书链构建: 从服务端证书逐级向上验证至根 CA。
- 主机名校验: 检查证书 CN 或 SAN 是否匹配请求域名。
- 有效期检查: 确认证书未过期且未生效。
- 吊销状态: 可选检查 CRL 或 OCSP(requests 默认不内置,需扩展)。
3.3 安全响应头处理
镜像源 HTTP 响应中携带的安全头直接影响供应链审计水位。requests 库本身不自动处理安全头,但 DevSecOps 巡检脚本必须检查以下关键头字段:
| 安全头名称 | 作用 | 审计水位要求 | requests 检查方式 |
|---|---|---|---|
Strict-Transport-Security |
强制后续请求使用 HTTPS | 必须存在,max-age ≥ 31536000 | resp.headers.get('Strict-Transport-Security') |
Content-Security-Policy |
限制资源加载来源 | 建议存在,至少包含 default-src 'self' | resp.headers.get('Content-Security-Policy') |
X-Content-Type-Options |
禁止 MIME 嗅探 | 必须为 nosniff |
resp.headers.get('X-Content-Type-Options') |
X-Frame-Options |
防止点击劫持 | 建议为 DENY 或 SAMEORIGIN |
resp.headers.get('X-Frame-Options') |
Cache-Control |
控制缓存策略,防止敏感数据缓存 | 建议包含 no-store |
resp.headers.get('Cache-Control') |
巡检脚本示例: 以下代码片段用于审计镜像源响应安全头,缺失或不符合水位要求的头将被记录到审计日志。
import requests
SECURITY_HEADERS = {
'Strict-Transport-Security': lambda v: v and 'max-age=31536000' in v,
'X-Content-Type-Options': lambda v: v == 'nosniff',
'Content-Security-Policy': lambda v: v is not None,
'X-Frame-Options': lambda v: v in ('DENY', 'SAMEORIGIN'),
}
def audit_security_headers(url):
try:
resp = requests.get(url, timeout=10, verify=True)
audit_results = {}
for header, check_fn in SECURITY_HEADERS.items():
value = resp.headers.get(header)
passed = check_fn(value)
audit_results[header] = {
'present': value is not None,
'value': value,
'passed': passed
}
return audit_results
except requests.exceptions.RequestException as e:
return {'error': str(e)}
# 审计示例
result = audit_security_headers('https://pypi.org/simple/')
for header, info in result.items():
status = '✅' if info.get('passed') else '❌'
print(f"{status} {header}: {info.get('value', '缺失')}")
3.4 证书固定与自定义信任策略
在内部镜像源或私有 PyPI 场景中,可能需要使用自签名证书或企业 CA。requests 支持通过 verify 参数指定自定义 CA 包,也支持通过 cert 参数提供客户端证书用于双向 TLS 认证。
import requests
# 场景一:使用自定义 CA 包验证服务端
resp = requests.get(
'https://internal-mirror.company.com/simple/',
verify='/etc/ssl/certs/company-ca.crt',
timeout=10
)
# 场景二:双向 TLS(mTLS)客户端证书
resp = requests.get(
'https://secure-mirror.company.com/simple/',
cert=('/path/to/client.crt', '/path/to/client.key'),
verify='/etc/ssl/certs/company-ca.crt',
timeout=10
)
权限审计要点: 在供应链巡检中,证书文件(
.crt、.key)的读取权限必须严格限制。巡检脚本应检查证书文件权限是否为 600 或 400,避免私钥泄露。
3.5 安全水位巡检清单
综合以上内容,针对 requests 库的 HTTPS 与证书安全巡检,建议按以下清单逐项检查:
- 协议版本: 确认服务端 TLS 版本 ≥ 1.2,拒绝旧版协议。
- 证书验证: 确保
verify=True,未使用verify=False的豁免配置。 - 证书链完整性: 检查证书链是否完整,根 CA 是否在信任库中。
- 主机名校验: 确认证书 CN/SAN 匹配请求域名。
- 安全响应头: 至少检查 HSTS、X-Content-Type-Options、CSP 三个头。
- 证书文件权限: 自定义 CA 或客户端证书文件权限不超过 600。
- 会话复用: 使用
requests.Session()时注意连接池的 TLS 上下文一致性。
自动化集成: 将上述巡检清单封装为
check_requests_tls_watermark() 函数,集成到 CI/CD 流水线中,每次镜像源同步前自动执行水位检查,不达标则阻断发布。