python -- NotOpenSSLWarning: urllib3 v2 only supports OpenSSL 1.1.1+

Python -- NotOpenSSLWarning: urllib3 v2 only supports OpenSSL 1.1.1+

一、背景与问题

在使用Python的urllib3库进行HTTPS请求时,开发者可能会遇到NotOpenSSLWarning警告。这个警告提示当前的urllib3版本(v2)仅支持OpenSSL 1.1.1及以上版本。该问题源于urllib3对OpenSSL的依赖版本要求,而当前系统中安装的OpenSSL版本可能低于1.1.1。

问题场景示例

在部署一个基于urllib3的API客户端时,服务器运行环境可能因系统更新策略导致OpenSSL版本过旧,从而触发该警告。例如:

$ pip install urllib3
  Could not find a version that satisfies the requirement urllib3>=2.0.0 (from versions: 1.26.0)
  You might want to include the whole dependency tree when reporting issues.
  Could not find a version that satisfies the requirement urllib3 (from versions: 1.26.0)

二、基本原理

1. OpenSSL版本与urllib3的兼容性

urllib3 v2+要求OpenSSL 1.1.1及以上版本,主要因为:

  • OpenSSL 1.1.1引入了更安全的TLSv1.3协议
  • 新版本支持更现代的加密算法(如AES-256-GCM)
  • 移除了旧版本中存在安全漏洞的特性(如SSLv2)

2. 系统环境差异

不同操作系统对OpenSSL的管理方式不同:

  • Linux系统通常通过apt/yum安装OpenSSL
  • macOS通过Homebrew安装
  • Windows系统可能通过MSVC工具链集成

三、环境准备

1. 检查当前OpenSSL版本

# Linux/macOS
openssl version

# Windows
# 打开命令提示符,输入:
# openssl version

2. 安装依赖

# 安装最新版本urllib3
pip install urllib3

# 安装OpenSSL开发包(Linux)
sudo apt-get install libssl-dev

# macOS
brew install openssl

四、核心实现

1. 检查OpenSSL版本

import ssl
import socket

def check_openssl_version():
    try:
        # 获取系统默认的SSL上下文
        context = ssl.create_default_context()
        # 获取SSL版本信息
        version = context._ssl_version
        print(f"Current OpenSSL version: {version}")
    except Exception as e:
        print(f"Error checking OpenSSL version: {e}")

2. 强制使用指定OpenSSL版本

import ssl
import socket
import urllib3

def force_openssl111():
    # 创建自定义SSL上下文
    context = ssl.create_default_context()
    context.options |= ssl.OP_NO_SSLv2
    context.options |= ssl.OP_NO_SSLv3
    context.options |= ssl.OP_NO_TLSv1
    context.options |= ssl.OP_NO_TLSv1_1
    
    # 设置自定义SSL上下文
    urllib3.util.ssl_.DEFAULT_SSL_CONTEXT = context
    
    # 测试连接
    http = urllib3.PoolManager()
    response = http.request('GET', 'https://example.com')
    print(response.status)

3. 禁用警告

import urllib3
urllib3.disable_warnings()

五、完整案例

1. 安全的HTTPS请求示例

import urllib3
import ssl

def safe_https_request(url):
    # 创建自定义SSL上下文
    context = ssl.create_default_context()
    context.check_hostname = True
    context.verify_mode = ssl.CERT_REQUIRED
    context.options |= ssl.OP_NO_SSLv2
    context.options |= ssl.OP_NO_SSLv3
    context.options |= ssl.OP_NO_TLSv1
    context.options |= ssl.OP_NO_TLSv1_1
    
    # 创建带自定义SSL上下文的PoolManager
    http = urllib3.PoolManager(
        ssl_context=context,
        cert_reqs=ssl.CERT_REQUIRED,
        ca_certs='/path/to/ca-bundle.pem'
    )
    
    # 发送请求
    response = http.request('GET', url)
    return response.data.decode('utf-8')

# 使用示例
if __name__ == "__main__":
    result = safe_https_request('https://api.example.com/data')
    print(result)

关键代码解释:

  1. ssl.create_default_context() 创建默认SSL上下文,自动加载系统CA证书
  2. 设置OP_NO_SSLv2等选项禁用旧版协议
  3. 通过ca_certs参数指定自定义CA证书文件
  4. 使用cert_reqs=ssl.CERT_REQUIRED强制验证服务器证书

六、源码解析

1. urllib3的SSL模块源码结构

# urllib3/util/ssl_.py
class SSLContext:
    def __init__(self):
        self._ssl_version = ssl.OPENSSL_VERSION
        self._ssl_options = 0

2. OpenSSL版本检测逻辑

# urllib3/util/ssl_.py
def get_openssl_version():
    return ssl.OPENSSL_VERSION

3. 自定义SSL上下文创建

# 自定义SSL上下文创建示例
context = ssl.create_default_context()
context.options |= ssl.OP_NO_SSLv2

七、进阶使用

1. 自定义证书验证

context = ssl.create_default_context()
context.load_verify_locations(cafile='/path/to/custom_ca.crt')

2. 证书链验证

context.check_hostname = True
context.verify_mode = ssl.CERT_REQUIRED

3. 高级配置示例

context = ssl.create_default_context()
context.set_ciphers('ECDHE-RSA-AES256-GCM-SHA384')
context.options |= ssl.OP_NO_TLSv1_2

八、性能与工程实践

1. 性能优化

  • 使用连接池:urllib3.PoolManager() 自动管理连接
  • 启用SSL会话复用:ssl.OP_NO_TICKET 优化TLS握手
  • 配置最大连接数:PoolManager(maxsize=100)

2. 安全风险分析

  • 忽略SSL验证可能导致中间人攻击
  • 使用过时的加密算法可能被破解
  • 不正确的CA证书配置可能导致证书验证失败

3. 安全配置建议

context = ssl.create_default_context()
context.set_ciphers('ECDHE-RSA-AES256-GCM-SHA384')
context.options |= ssl.OP_NO_SSLv2
context.options |= ssl.OP_NO_SSLv3
context.options |= ssl.OP_NO_TLSv1
context.options |= ssl.OP_NO_TLSv1_1

九、常见问题与踩坑

1. 常见错误

  • 错误1:忽略SSL验证导致数据泄露

    context.check_hostname = False  # 错误配置
  • 错误2:未正确配置CA证书导致连接失败

    context.load_verify_locations(cafile='nonexistent.crt')  # 错误配置

2. 解决方案

  • 使用ssl.create_default_context()自动加载系统CA证书
  • 避免手动设置check_hostname=False,应使用cert_reqs=ssl.CERT_REQUIRED
  • 使用ssl.get_default_verify_paths()获取系统证书路径

3. 常见陷阱

  • 错误使用ssl.SSLContext.wrap_socket()导致连接失败
  • 忽略系统更新导致的版本不兼容问题
  • 未正确处理证书链导致的验证失败

十、最佳实践

1. 推荐方案

  • 使用urllib3.PoolManager管理连接池
  • 按需配置SSL选项,禁用不安全协议
  • 使用ssl.create_default_context()自动处理CA证书
  • 定期更新OpenSSL版本至1.1.1+

2. 避免使用场景

  • 不需要HTTPS通信的简单场景
  • 使用更简单的HTTP客户端(如requests库)
  • 临时测试环境不需要严格的SSL验证

3. 方案比较

方案优点缺点
原生urllib3精度控制配置复杂
requests简单易用难以深度控制SSL配置
aiohttp异步支持需要额外依赖

十一、总结

NotOpenSSLWarning是urllib3对OpenSSL版本的兼容性提示,反映了Python网络库对安全性的严格要求。在实际开发中,需要根据系统环境和业务需求,合理配置SSL选项,确保通信安全。通过合理使用SSL上下文配置、证书验证和连接池管理,可以在保证安全性的前提下优化性能。开发人员应定期检查依赖库版本,及时更新OpenSSL以避免潜在安全风险。在涉及敏感数据传输的场景中,务必严格配置SSL参数,防止中间人攻击和数据泄露。

最后修改于:2026年09月20日 14:42

评论已关闭

推荐阅读

AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日
python之plot()和subplot()画图
2024年11月26日
理解 DALL·E 2、Stable Diffusion 和 Midjourney 工作原理
2024年12月01日