aiohttp WebSocket 关闭码校验修复:拒绝对端 Close 帧中的 1006(ABNORMAL_CLOSURE)
后端Web框架WebSocket【免费下载链接】aiohttpAsynchronous HTTP client/server framework for asyncio and Python项目地址https://gitcode.com/gh_mirrors/ai/aiohttp点击查看免费下载导读本文围绕 aiohttp 的 bugfix 变更CHANGES/13536.bugfix.rst展开WebSocket Reader 此前会错误地接受对端 Close 帧中携带的关闭码1006而根据 RFC 64551006属于保留码禁止出现在网络传输的 Close 帧中。文章将结合仓库源码与测试用例剖析该问题的成因、修复后的校验逻辑、Python/Cython 双实现路径以及1006在 aiohttp 内部作为本地状态码WSCloseCode.ABNORMAL_CLOSURE的正当用法帮助读者理解 WebSocket 协议合规性校验的底层实现。一、问题背景RFC 6455 中的关闭码语义WebSocket 协议RFC 6455定义了 Close 控制帧用于在连接两端主动终止会话时传递一个 2 字节的关闭状态码close code和可选的文本原因。关闭码被划分为几个区间1000–2999协议保留区间其中1000–1015是固定语义的预定义码3000–3999留给库、框架和应用自行注册使用4000–4999供私有应用使用。其中1006ABNORMAL CLOSURE是一个特殊的存在它被 RFC 6455 第 7.4.1 节定义为连接在缺少 Close 帧的情况下异常关闭的语义仅供本地实现内部标记使用绝不能作为帧内容在网络上发送。同理1004保留、1005无状态码、1015TLS 握手失败也都是禁止上线的保留码。aiohttp 在 aiohttp/_websocket/models.py 中通过WSCloseCode枚举完整登记了这些预定义码class WSCloseCode(IntEnum): OK 1000 GOING_AWAY 1001 PROTOCOL_ERROR 1002 UNSUPPORTED_DATA 1003 ABNORMAL_CLOSURE 1006 INVALID_TEXT 1007 POLICY_VIOLATION 1008 MESSAGE_TOO_BIG 1009 MANDATORY_EXTENSION 1010 INTERNAL_ERROR 1011 SERVICE_RESTART 1012 TRY_AGAIN_LATER 1013 BAD_GATEWAY 1014注意ABNORMAL_CLOSURE 1006是枚举成员之一aiohttp 在本地用它标记连接异常中断但这不意味着它可以被写入 Close 帧对外发送——这正是本次 bugfix 修复的边界问题。二、问题本身Reader 误接受对端下发的 1006在修复之前WebSocket Reader 在解析 Close 帧时对关闭码的合法性检查存在漏洞导致对端peer在 Close 帧中携带1006时会被当作合法值接受而不是按协议要求以1002 PROTOCOL_ERROR拒绝。这个问题的严重性在于违反 RFC 6455 的显式规定1006不应出现在线上帧中在 aiohttp 内部1006有专门含义连接异常关闭若被当作对端显式关闭码透传给上层应用会造成语义混淆——应用层会分不清对端发来了 1006与本地检测到连接异常协议解析器作为安全边界接受非法状态码可能成为畸形/不规范实现混入的入口。三、修复方案ALLOWED_CLOSE_CODES 白名单校验修复的核心在 aiohttp/_websocket/reader_py.py。源码通过构造一个允许上线的关闭码集合显式把1006排除在外# ABNORMAL_CLOSURE is used internally, should never be accepted from a client. # https://datatracker.ietf.org/doc/html/rfc6455#section-7.4.1 ALLOWED_CLOSE_CODES {int(i) for i in WSCloseCode} - { int(WSCloseCode.ABNORMAL_CLOSURE) }这一行注释直接点明了本次修复的设计意图ABNORMAL_CLOSURE仅供内部使用绝不应从对端接受。随后的 Close 帧处理逻辑reader_py.py在解出 2 字节关闭码后执行完整的合法性判定elif opcode OP_CODE_CLOSE: payload_len len(payload) if payload_len 2: close_code UNPACK_CLOSE_CODE(payload[:2])[0] # https://datatracker.ietf.org/doc/html/rfc6455#section-7.4.2 if close_code 4999 or ( close_code 3000 and close_code not in ALLOWED_CLOSE_CODES ): raise WebSocketError( WSCloseCode.PROTOCOL_ERROR, fInvalid close code: {close_code}, ) ...校验规则可以拆解为两条条件判定结果close_code 4999含5000–65535超出合法区间报1002 PROTOCOL_ERRORclose_code 3000且不在ALLOWED_CLOSE_CODES中属于保留/禁止码如1004、1005、1006、1015报1002 PROTOCOL_ERROR由于ALLOWED_CLOSE_CODES是从WSCloseCode枚举全集剔除1006后得到的因此1006必然落入第二条分支被拒绝。修复后任何携带1006的 Close 帧都会触发WebSocketErrorcode1002该异常会经由feed_data的异常捕获路径reader_py.py写入队列最终以上层可见的协议错误形式暴露给调用方。此外Close 帧还有其他合规性校验payload 长度必须为 0 或 ≥21 字节的 payload 会被判定为非法见 reader_py.pypayload 中的文本部分必须是合法 UTF-8否则报1007 INVALID_TEXT。四、Python 与 Cython 双实现修复如何覆盖两条代码路径aiohttp 的 WebSocket 解析器存在双实现架构纯 Python 实现aiohttp/_websocket/reader_py.pyCython 加速实现aiohttp/_websocket/reader_c.pxd 定义了WebSocketReader/WebSocketDataQueue的 C 级接口模块入口 aiohttp/_websocket/reader.py 负责按运行环境选择实现当NO_EXTENSIONS为真或 Cython 扩展导入失败时回退到 Python 版本否则优先加载编译后的reader_c版本。ALLOWED_CLOSE_CODES这个集合在 reader_c.pxd 中被声明为cdef set与 Python 实现共享同一份语义定义——因此本次校验修复对两条代码路径同时生效无论用户安装的是纯 Python 包还是带 Cython 扩展的预编译 wheel行为一致。从实现细节看_handle_frame的 close 分支同样在 Cython 版本中通过cpdef暴露reader_c.pxd关闭码的解析借助UNPACK_CLOSE_CODE字节解包辅助函数完成确保 Python 与 C 路径的校验结果严格等价。五、测试验证保留码参数化用例仓库测试 tests/test_websocket_parser.py 为本次修复提供了直接的回归保护pytest.mark.parametrize(code, (1004, 1005, 1006, 1015)) def test_close_frame_reserved_code(parser: PatchableWebSocketReader, code: int) - None: # https://datatracker.ietf.org/doc/html/rfc6455#section-7.4.1 # 1004, 1005, 1006 and 1015 are resreved and forbidden as a # status code in a Close frame on the wire. 1006 is a WSCloseCode member # (aiohttp uses it locally), so it must still be rejected on receipt. data build_close_frame(codecode) with pytest.raises(WebSocketError) as ctx: parser._feed_data(data) assert ctx.value.code WSCloseCode.PROTOCOL_ERROR该测试的注释与源码注释相互印证1006虽然是WSCloseCode枚举成员本地使用但在接收时必须拒绝。测试将1004、1005、1006、1015四个保留码统一参数化确保它们全部被解析器以PROTOCOL_ERROR拒绝。同一测试文件中还有配套的边界用例test_websocket_parser.py覆盖5000、9999、65535等超出4999上限的非法关闭码与白名单逻辑形成完整闭环。六、1006 在 aiohttp 内部的正当用法ABNORMAL_CLOSURE修复并没有移除1006的枚举定义——它在 aiohttp 内部依然承担重要职责只是使用场景被严格限定在本地状态标记而非线上帧内容。在功能测试中可以看到WSCloseCode.ABNORMAL_CLOSURE被用来断言连接异常关闭的结果tests/test_client_ws_functional.py 等多处断言resp.close_code is WSCloseCode.ABNORMAL_CLOSURE即客户端在连接被异常中断未收到 Close 帧时本地记录关闭码为1006tests/test_web_websocket_functional.py 等服务端测试同样用ws.close_code WSCloseCode.ABNORMAL_CLOSURE断言异常断开场景。也就是说1006在 aiohttp 的语义是对端没有发送 Close 帧就断开了连接——这是本地检测到的异常状态close_code属性会以ABNORMAL_CLOSURE呈现给应用层。这与从线上帧中解析出 1006是完全不同的两条路径。本次 bugfix 的意义正在于堵住后一条路径既然1006是本地状态的专属标记那么任何从对端帧中宣称1006的行为都必然是非法的协议数据必须被解析器以1002 PROTOCOL_ERROR拒绝而不能混入本地状态标记中。七、对使用者的影响与升级建议行为变化升级到包含该修复的版本后如果对端客户端或服务端在 Close 帧中携带1006aiohttp 不再将其透传为关闭码而是抛出WebSocketErrorcode1002并触发连接关闭。这符合 RFC 6455 对保留码的规定属于协议合规性收紧。自查对端实现若你的应用需要与某些不规范实现的 WebSocket 服务端/客户端互通请确认对端不会在 Close 帧中发送1006或1004、1005、1015。规范的做法是仅在本地用1006标记连接异常线路上永远不发送它。应用层判断逻辑不变ws.close_code仍会在连接异常中断时返回WSCloseCode.ABNORMAL_CLOSURE本地语义这部分行为未受影响受影响的是对端帧中显式携带 1006这一非法输入的处理。关注测试入口如需验证自己的构建版本是否包含该修复可直接运行 tests/test_websocket_parser.py 中的test_close_frame_reserved_code参数化用例观察1006是否被拒绝。小结本次 bugfix 以一段精巧的白名单集合ALLOWED_CLOSE_CODES WSCloseCode 全集 - {1006}修复了 WebSocket Reader 对保留关闭码的校验漏洞使 aiohttp 在拒绝非法关闭码与本地使用 1006 标记异常关闭两条语义之间划清了边界。从 models.py 的枚举定义、reader_py.py 的校验实现到 reader_c.pxd 的 Cython 双路径覆盖再到 test_websocket_parser.py 的回归测试仓库中形成了完整一致的协议合规性闭环——这正是 aiohttp 作为 asyncio 生态 WebSocket 实现所应具备的严谨性。赞分享后端Web框架WebSocket【免费下载链接】aiohttpAsynchronous HTTP client/server framework for asyncio and Python项目地址https://gitcode.com/gh_mirrors/ai/aiohttp点击查看免费下载相关推荐aiohttp WebSocket CLOSE 帧状态码校验按 RFC 6455 拒绝越界关闭码4999的协议错误处理aiohttp WebSocket CLOSE 帧状态码校验按 RFC 6455 拒绝越界关闭码 4999的协议错误处理 导读 本文围绕 aiohttp后端Web框架WebSocketaiohttp WebSocket 分片消息协议校验修复严格按 RFC 6455 拒绝分片间注入的数据帧aiohttp WebSocket 分片消息协议校验修复严格按 RFC 6455 拒绝分片间注入的数据帧 本篇技术指南围绕 aiohttp 的 WebSock后端Web框架WebSocketaiohttp WebSocket 大消息整型溢出漏洞修复解析从 max_msg_size 校验到 1009 关闭码aiohttp WebSocket 大消息整型溢出漏洞修复解析从 max_msg_size 校验到 1009 关闭码 导读 本文基于 aiohttp 官方变更后端Web框架WebSocket上一篇Unlock Music 使用指南3 步在浏览器中解锁加密音乐无需安装下一篇craft-agents-oss 0.2.33 版本技术解析OAuth 认证统一、~/.claude.json 自动修复与稳定性加固创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

QQ空间备份 3 步搞定:用 GetQzonehistory 完整导出历史说说

QQ空间备份 3 步搞定:用 GetQzonehistory 完整导出历史说说

QQ空间备份 3 步搞定:用 GetQzonehistory 完整导出历史说说 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory GetQzonehistory 是一个开源工具,用来备份QQ空间说说…

2026/9/21 22:53:51 阅读更多 →
离线文字识别怎么做?开源OCR工具 Umi-OCR 完整指南

离线文字识别怎么做?开源OCR工具 Umi-OCR 完整指南

离线文字识别怎么做?开源OCR工具 Umi-OCR 完整指南 【免费下载链接】Umi-OCR OCR software, free and offline. 开源、免费的离线OCR软件。支持截屏/批量导入图片,PDF文档识别,排除水印/页眉页脚,扫描/生成二维码。内置多国语言库…

2026/9/21 22:52:50 阅读更多 →
黑苹果 EFI 配置不用手抄:OpCore-Simplify 5 步从下载到进系统的完整实测

黑苹果 EFI 配置不用手抄:OpCore-Simplify 5 步从下载到进系统的完整实测

黑苹果 EFI 配置不用手抄:OpCore-Simplify 5 步从下载到进系统的完整实测 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 上周朋友拿台老笔…

2026/9/21 22:52:50 阅读更多 →

最新新闻

石察卡图解原理:3个核心考点拆解版本升级痛点

石察卡图解原理:3个核心考点拆解版本升级痛点

石察卡图解原理:3个核心考点拆解版本升级痛点 版本升级后 API 全变了,石察卡图解原理能救命。 别再对着报错日志发呆,大厂面试最爱问这个。 用图解原理看透石察卡,面试直接拿高分。 考点梳理:为什么石察卡成为高频面试题…

2026/9/22 2:27:22 阅读更多 →
应的繁体字避坑指南:3步搞定环境配置完整示例

应的繁体字避坑指南:3步搞定环境配置完整示例

应的繁体字避坑指南:3步搞定环境配置完整示例 配置环境就卡半天,这种痛谁懂?很多开发者在搭建项目时,因为一个不起眼的字符编码问题,导致依赖安装失败、构建报错,甚至前端页面出现乱码。今天要解决的核心痛点,就是“应的繁体字”这一类特殊字符在不同…

2026/9/22 2:27:21 阅读更多 →
成都入户性能优化源码解析:3步解决报错堆积

成都入户性能优化源码解析:3步解决报错堆积

成都入户性能优化源码解析:3步解决报错堆积 盯着屏幕上一长串红色的 StackTrace,心里那个慌啊。每一行调用栈都像天书,尤其是当业务逻辑嵌套了七八层,报错信息指向某个陌生的类名时,根本不知道从哪下手。很多刚接触后端开发的兄弟,面对这种…

2026/9/22 2:27:21 阅读更多 →
剑三抓马插件性能优化实战:3个底层原理让你面试不再卡壳

剑三抓马插件性能优化实战:3个底层原理让你面试不再卡壳

剑三抓马插件性能优化实战:3个底层原理让你面试不再卡壳 面试被问原理答不上来,是无数转岗开发者的噩梦。当你还在纠结业务逻辑时,面试官却盯着底层实现追问细节,这种落差感让人窒息。今天不讲虚的,直接拆解【剑三抓马插件】在【性能优化】上的底层逻辑…

2026/9/22 2:27:21 阅读更多 →
文字扫描识别软件面试避坑:3个核心考点助你搞定性能优化

文字扫描识别软件面试避坑:3个核心考点助你搞定性能优化

文字扫描识别软件面试避坑:3个核心考点助你搞定性能优化 很多开发者学了 OCR 基础语法,却卡在“怎么把识别准确率提到 99% 以上”这一步。别慌,这正是面试大厂时最容易被问到的 性能优化…

2026/9/22 2:26:20 阅读更多 →
车架号查询车辆信息实战:5种后端方案对比与最佳实践

车架号查询车辆信息实战:5种后端方案对比与最佳实践

车架号查询车辆信息实战:5种后端方案对比与最佳实践 学会语法却不知怎么搭项目?这是很多开发者从教程走向生产环境时最大的拦路虎。尤其是面对像 车架号查询车辆信息 这种典型的高频业务场景,很多人只会写 SELECT * FROM cars…

2026/9/22 2:26:20 阅读更多 →

日新闻

3台商务办公笔记本实测:手写实现环境配置,告别卡半天

3台商务办公笔记本实测:手写实现环境配置,告别卡半天

3台商务办公笔记本实测:手写实现环境配置,告别卡半天 配置环境就卡半天?别怪机器慢,多半是你没选对工具链。在Java、Go或Python的项目现场, 手写实现…

2026/9/22 0:00:41 阅读更多 →
剑帝加点速查手册:3分钟搞懂核心逻辑

剑帝加点速查手册:3分钟搞懂核心逻辑

剑帝加点速查手册:3分钟搞懂核心逻辑 面试被问原理答不上来,是不是常态?别慌。很多开发者对着 GitHub 开源仓库里的代码发呆,看似简单实则暗藏玄机。今天这份【剑帝加点】速查手册,直接带你拆解核心实现,把面试必考的原理讲透。…

2026/9/22 0:00:41 阅读更多 →
手写实现图片压缩网站核心:搞定WebP转换与质量调优

手写实现图片压缩网站核心:搞定WebP转换与质量调优

手写实现图片压缩网站核心:搞定WebP转换与质量调优 复制来的代码跑不通不知道怎么调?别慌,这种“复制粘贴地狱”在开发圈太常见了。尤其是做 图片压缩网站…

2026/9/22 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/21 3:13:20 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/21 2:19:36 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/21 4:51:05 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/21 15:36:51 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/21 15:36:51 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →