Windows系统证书损坏导致的SSL致命错误以及docker下载问题
一、前言***之前下载python运行环境都依赖Windows系统的根证书出现了这个错误报错就显示说aiohttp库尝试加载 Windows 系统根证书时发现证书存储中存在数据不完整或格式损坏的证书导致 SSL 上下文初始化失败。 ssl.SSLError: [ASN1: NOT_ENOUGH_DATA]这个报错是在项目下的虚拟环境下运行的不知道是不是虚拟环境下OpenSSL 库本身损坏。于是打算在powershell终端的base环境下验证底层SSL是否正常、aiohttp是否能正常导入。下面是powershell的命令# 切换到之前报错的虚拟环境 conda activate llm_conda # 1. 测试底层SSL是否正常 python -c import ssl; ssl.create_default_context(); print(SSL正常) # 2. 测试aiohttp是否能正常导入 python -c import aiohttp; print(aiohttp版本:, aiohttp.__version__)执行命令以后显示结果正常但是这不能直接排除系统证书损坏的问题。因为两个环境的 Python 版本、OpenSSL 底层库版本可能完全不同对证书格式的校验严格程度不一样。因此 base 环境正常不代表 虚拟环境环境也正常。于是我在虚拟环境里面继续执行在base里的两行测试命名检测底层SSL是否正常、测试aiohttp是否能正常导入最后发现果然是系统证书出现了问题。第一条测试第二条测试上面两张图片展示了Windows 系统下 Anaconda 环境llm_conda中执行 Python 命令时出现的 SSL 相关错误。核心问题是Python 无法正确加载 SSL 默认上下文CA 证书导致网络请求如aiohttp失败。其中ssl.create_default_context()尝试加载系统默认的CA 证书用于验证 HTTPS 网站身份。NOT_ENOUGH_DATA错误表示CA 证书数据不完整或缺失导致 SSL 握手无法完成。所有依赖 SSL 的 Python 库如requests,aiohttp,urllib都会受影响。***除此以外下载docker desktop遇见了WSL错误导致出现docker乱码和 0xffffffff 错误。排查一圈后发现可能是安装了某些软件、杀毒软件或企业安全代理如 Cisco AnyConnect, Zscaler之后它们可能会修改系统证书存储或者说中啥病毒了之前也没有乱删除什么系统文件。二、报错原因2.1 第一次原因分析datasets库 → aiohttp库 → ssl模块 → 加载Windows系统证书 → 发现损坏证书/格式不正确 → 抛出ASN1解析错误。所以任何使用aiohttp/requests的Python库都会出现这个错误。Python 的ssl模块会批量读取所有系统根证书只要有一个证书格式损坏、ASN.1 结构解析失败就会整体报错导致aiohttp、requests等所有依赖 SSL 的库都无法导入。2..2 最终原因根本原因就是新旧环境的 OpenSSL 版本对畸形证书的容忍度不同。certifi 元数据损坏site-packages 下同时存在 3 个 certifi-*.dist-info 目录 2026.4.22 / 2026.6.17 / 2026.7.22 其中一个 METADATA 缺失导致 pip list 显示 certifi NoneWindows 证书存储 OpenSSL 3.5.7 冲突Windows 系统证书存储ROOT/CA里有 1 条损坏的证书数据 ASN.1 结构不完整。新建环境没问题是因为它用 OpenSSL 3.5.6 对损坏证书容忍度更高/跳过而 旧环境 用的 OpenSSL 3.5.7 解析更严格在 ssl._load_windows_store_certs() 读取这条坏证书时直接抛 [ASN1: NOT_ENOUGH_DATA] 整个 create_default_context() 崩溃连带着所有 urllib 、 http.client 的默认 HTTPS 请求全部失败。三、解决方案1.docker乱码和 0xffffffff 错误我遇到的是最经典的旧版 WSL 问题--version参数是WSL 2.0 版本才有的你的系统里安装的是 Windows 自带的老旧 收件箱 版 WSL 1这也是 Docker Desktop 报错的根本原因新版 Docker 只支持 WSL 2。1卸载现有内核重新安装WSL内核即可。# 直接在管理员PowerShell中执行以下命令自动下载安装 #执行这个关键命令直接从微软官网下载最新 WSL 2跳过 Microsoft Store wsl --update --web-download #等待下载安装完成会提示 已成功更新适用于 Linux 的 Windows 子系统 #必须重启电脑这一步绝对不能跳过2等待安装完成后再次测试#在powershell中输入 wsl --version此时应该能正常显示版本信息没有乱码。成功标志正常显示类似以下的版本信息没有乱码没有 命令行选项无效WSL 版本 2.3.24.0 内核版本 5.15.153.1-2 WSLg 版本 1.0.65 MSRDC 版本 1.2.5620 Direct3D 版本 1.611.1-81528511 DXCore 版本 10.0.26091.1-240330-1435.ge-release Windows 版本 10.0.22631.38802.ssl系统证书错误1换更稳定的requests库来替代 aiohttp库 一个异步 HTTP 库这样可以完全避开对aiohttp的依赖从而绕过这个 SSL 错误。这里以调用搜索工具查天气为例子。from langgraph.prebuilt import ToolNode from langgraph.graph import StateGraph, MessagesState, START, END from langchain.chat_models import init_chat_model # 1. 删除这行from langchain_tavily import TavilySearch import requests import os from dotenv import load_dotenv from langchain.tools import tool load_dotenv() llm init_chat_model(api_keyos.getenv(DASHSCOPE_API_KEY), base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1, model_provideropenai, modelMiniMax-M2.1) # 2. 使用 tool 自定义工具直接请求 Tavily API tool def tavily_search_tool(query: str) - str: 这是一个搜索工具 api_key os.getenv(TAVILY_API_KEY) if not api_key: return Error: TAVILY_API_KEY not found in environment variables. url https://api.tavily.com/search payload { api_key: api_key, query: query, search_depth: basic, max_results: 5 } try: response requests.post(url, jsonpayload) response.raise_for_status() data response.json() # 这里简单返回结果也可以根据 data[answer] 或 data[results] 进行格式化 return str(data) except Exception as e: return fError occurred during search: {str(e)} tool_node ToolNode([tavily_search_tool]) model_with_tools llm.bind_tools([tavily_search_tool]) def should_continue(state: MessagesState): messages state[messages] last_message messages[-1] if last_message.tool_calls: return tools return END def call_model(state: MessagesState): messages state[messages] response model_with_tools.invoke(messages) return {messages: [response]} builder StateGraph(MessagesState) builder.add_node(call_model, call_model) builder.add_node(tools, tool_node) builder.add_edge(START, call_model) builder.add_conditional_edges(call_model, should_continue, [tools, END]) builder.add_edge(tools, call_model) graph builder.compile() print(graph.invoke({messages: [{role: user, content: 明天北京的天气如何}]}))2直接删除高频损坏证书再让系统自动更新恢复干净证书根治这个操作不太建议删错风险很大不建议操作。并且新增证书的话也可能安装到不那么正规的证书风险很大。3新建虚拟环境试了一下成功了。新虚拟环境正常、旧环境报错 那就是旧环境独有的配置 / 证书文件干扰或者版本/文件损坏造成的干扰。不放心又去测试了第二遍下面是SSL测试代码。import ssl import urllib.request import sys def test_ssl(): print(f当前使用的 Python 路径: {sys.executable}\n) # 1. 测试 ssl 模块基础信息和证书路径 print(1. SSL 模块基础信息:) print(f OpenSSL 版本: {ssl.OPENSSL_VERSION}) # 2. 尝试发起真实的 HTTPS 请求访问百度国内响应最快 url https://www.baidu.com print(f\n2. 尝试发起 HTTPS 请求: {url}) try: # 创建一个默认的 SSL 上下文会加载系统证书库 context ssl.create_default_context() print( SSL 上下文创建成功说明证书库读取没有崩溃...) # 发起请求 req urllib.request.Request(url, headers{User-Agent: Mozilla/5.0}) response urllib.request.urlopen(req, timeout5, contextcontext) print(f\n 成功服务器返回状态码: {response.status}) print( SSL 模块和系统证书均工作正常) except urllib.error.URLError as e: print(f\n 失败网络请求报错:) print(f 错误详情: {e.reason}) except Exception as e: print(f\n 失败发生未知错误:) print(f 错误详情: {e}) if __name__ __main__: test_ssl()下面是SSL模块和系统证书正常的输出4通过 certifi 绕过 Windows 系统证书既然 Windows 自带的证书库靠不住我们就彻底不让 Python 去碰它而是改用certifi自带的一套纯净、跨平台、由 Mozilla 维护的第三方证书库。不过因为使用的是 Mozilla 维护的公共证书库如果公司内网使用了自签发的内部 HTTPS 证书通过这种方式访问内网可能会被拦截需要手动将内网证书加入certifi的cacert.pem中。四、小结4.1 SSL握手为什么客户端和服务器要进行SSL握手呢什么是SSL握手这就涉及到网络安全了服务器和客户端进行通讯的时候要确保双方身份是真的不是伪造的进行身份验证、传输的数据加密过就算被第三方看到也看不懂传输了什么数据协商加密、以及传输中途数据没有被黑客偷偷掉包数据完整。这跟SSL模块有什么关系呢SSL 模块本身是一套完整的“安全通信协议规则与流程。它本身并不从头编写加密算法那些复杂的数学运算通常由底层的 C 语言库比如OpenSSL来完成。SSL作用是给 Python 开发者提供了简单易用的函数接口比如截图里的ssl.create_default_context()它自动执行代码帮你管理证书、协商加密算法、校验数据完整性把普通的、不安全的网络连接Socket包裹上一层“安全装甲”变成安全的 SSL Socket。而查看系统证书就是SSL在进行身份验证如果你的电脑的系统证书是全球公认的、权威的“发证机关”CA机构的印章和签名样本根证书并且没过期或者证书数据没有缺失或读取失败身份才是合格的。我这里是Python 在读取本地系统证书库时发现数据缺失或读取失败导致无法进行身份验证所以报错。网址里的https比http多出来的那个sSecure/安全就是靠这个握手过程来实现的。4.2 依赖、环境报错简单思路最简单的思路是换个环境等有空了再去排查细节问题这样效率才高不然主任务会被拖累。