30 个字符的输入让一次正则卡 3 秒、比线性写法慢 3800 万倍:正则「再慢也有限」这条共识的实测复盘
2026 年开年到现在CVE 库里已经躺了 40 多个 ReDoSCWE-1333漏洞picomatch 的 extglob 嵌套量词CVE-2026-33671、Open WebUI 的$...重叠量词CVE-2026-59220、Sentry ingestion 管道CVE-2026-52794、Apache Superset 的SQL_REGEXCVE-2026-23985、连 MCP TypeScript SDK 的 UriTemplate 都没逃过CVE-2026-0621。它们有一个共同的可怕之处Node 是单线程事件循环一个正则的灾难性回溯不是“慢一条请求”而是把整个进程冻住所有并发用户一起挂。我一度也信那句“正则再慢也有限小输入更无所谓”。于是把一个带嵌套量词的“纯单词校验器”和它的线性改写拉到同一张基准上用对抗输入跑了中位数——结论和这句共识相去甚远。背景为什么正则的“慢”值得当成安全议题正则几乎是每一行代码都在用的“小操作”表单校验、日志解析、路由匹配、模板渲染、协议头解析……单次看着便宜可它跑在请求热路径上又吃着单线程事件循环的“全局锁”。一旦某个 pattern 在特定输入下退化成指数时间攻击者只需发一个几十字符的字符串就能用一次 CPU 峰值把服务打瘫——这正是上面那一串 CVE 的共性。问题出在“共识”两个字。大家默认正则耗时随输入长度线性增长却很少想清楚回溯型引擎V8、PCRE、Pythonre默认都是在遇到“嵌套量词”或“重叠分支”时最坏情况是指数级。而更阴险的是——这种爆炸只在对抗/边界输入下发生正常输入下它跑得飞快于是代码评审和单元测试全都看不见。解剖回溯引擎怎么被一个嵌套量词拖进指数坑回溯引擎匹配失败时不会乖乖放弃而是把已经吃掉的字符合回去、换一种分法再试。(\w)这个结构就是典型的陷阱外层要把“一串单词字符”再分成若干个\w组。当输入是aaa...a!全是a、结尾一个非单词字符时引擎必须穷举所有可能的分组方式才能确认“整体不匹配”——而 n 个a分成若干正长度组的方式一共有2^(n-1)种。图1(\w)的回溯树。输入一旦无法整体匹配引擎就从右往左“吐”字符、换一种分组再试路径数随长度指数级膨胀。这不是学术玩具。上面那些 CVE 全是一个模子picomatch 的((?:...))、Open WebUI 的$...重叠量词、Superset 的重叠析取——本质都是“让引擎在失败时去穷举指数种路径”。下面用最干净的^(\w)$复现它。实证一同一个校验器对抗输入下指数爆炸把“校验字符串只含单词字符”这件小事先用带嵌套量词的^(\w)$evil再用没有嵌套的^\w$safe喂给非匹配输入a重复 N 次加一个!。Node v22、每组取中位数输入长度 nevil 单次耗时safe 单次耗时evil 比 safe 慢80.0010 ms0.00003 ms33×120.0109 ms0.00003 ms388×160.1727 ms0.00003 ms5,080×202.8469 ms0.00003 ms88,967×2445.2665 ms0.00003 ms1,414,578×28767.5272 ms0.00008 ms9,594,090×303034.8717 ms0.00008 ms37,935,896×规律肉眼可见每多一个字符耗时约翻一倍每多两个字符约翻四倍。n24时一次test()已经 45ms——单这一个调用就超过了 60fps 的 16.6ms 帧预算n30时一个 30 字符的字符串让一次正则卡了 3 秒比线性写法慢了3800 万倍。在 Node 里这 3 秒事件循环全程被这一个调用独占。图2同一语义两种写法在对抗输入下的耗时天差地别。evil 那条线每加一个字符就翻一倍safe 始终贴地。实证二合法输入秒回、删掉嵌套就线性收场为什么这种炸弹能混过评审因为它在合法输入下跑得飞快。把上面同一个 evil 喂给能匹配的a重复 N 次没有结尾的!输入长度 nevil 匹配耗时safe 匹配耗时5120.00025 ms0.00022 ms32,7680.00666 ms0.00629 ms524,288半百万0.12967 ms0.10187 ms半百万字符的合法输入evil 也只花 0.13ms和 safe 几乎一样——单元测试全用合法数据永远不会触发爆炸。这正是 ReDoS 最危险的地方它只在对抗/边界输入下现身。而“修复”其实简单到反直觉把嵌套量词拆掉^(\w)$直接写成^\w$语义完全不变都是“整串只含单词字符”却在对抗输入下从 3 秒变成 0.00008ms。差异不在算法而在有没有给引擎制造指数种失败路径。图3随着长度增加evil 与 safe 的差距从千倍一路拉到千万倍safe 那根柱子在图里几乎看不见。那“给输入限个长度”总行了吧实测给 evil 限长上限 20 → 最坏约 3ms勉强可接受上限 30 → 最坏约 3秒。因为耗时每字符翻倍任何没实测过上限的“合理长度限制”比如 1KB都等于没限制——n40时会是约 52 分钟的一次调用。长度上限是止血不是解药。局限长度上限只是止血、JS 没有占有量词诚实边界避免被当成“银弹”长度上限必要但不足它只能把 DoS 压到“你实测过的那个上限对应的耗时”。上限取 20 还有 3ms 的单调用取 30 就已经 3 秒——你必须针对具体 pattern 实测上限不能拍脑袋写if (len 1024)。JS 没有占有量词 / 原子组在 PCRE、Java 里你可以写(?...)或a*来“锁死”回溯但JavaScript 的RegExp至今不支持这两者a*直接语法报错。所以“加个占有量词”这条在其他语言管用的招在 Node/浏览器里用不了。真正的解药是线性引擎对不可信 / 用户提供的 pattern靠手写改写不够稳应改用线性时间引擎Google RE2、Rustregex、Node 的re2绑定——它们底层是 DFA/游程结构上杜绝了回溯爆炸。上面那些 CVE 的修复要么删掉重叠量词Sentry、Open WebUI要么升级到已打过补丁的版本picomatch 2.3.2/4.0.4方向一致。静态扫描兜底用vuln-regex-detector、semgrep的 ReDoS 规则在 CI 里扫嵌套量词和重叠析取比靠人眼评审靠谱。数字来自单台机器Windows / AMD64 / Node v22的中位数不同 V8 版本、不同 CPU 会有浮动但“指数而非线性”的形状对所有回溯型 NFA 引擎都成立。结论与下一步一句话方法论别再信“正则再慢也有限”。正则耗时在对抗输入下是指数而非线性——一个 30 字符的字符串就能让一次test()卡 3 秒、比线性写法慢 3800 万倍而它只在边界输入下现身单元测试根本发现不了。修法是三件事删掉嵌套量词与重叠析取如(\w)→\w、对不可信 pattern 改用线性引擎、长度上限必须针对具体 pattern 实测而不是拍脑袋。开源地址矩阵门户GitHub - wangzifan396-wzf/WB: nano-tools: 1200 single-file, zero-dependency, local-first web utilities in one portal. Offline and private, nothing leaves your browser. Binary protocol parsers, crypto, dev, audio, visualization, productivity. · GitHub单文件工具聚合器GitHub - wangzifan396-wzf/nano-workbench: Single-file tabbed launcher for the nano-tools matrix - one tab, 382 curated tools (of 1228), instant switching. Zero-dep. Part of nano-tools. · GitHubGitHub 组织主页wangzifan396-wzf (WangZi) · GitHub

相关新闻

Adapting Large Language Models to Low-Resource Tibetan: A Two-Stage Continual and Supervised Fine...

Adapting Large Language Models to Low-Resource Tibetan: A Two-Stage Continual and Supervised Fine...

文章核心总结与翻译 一、主要内容 本文针对藏语这一低资源语言(数据稀缺、形态复杂且代表性不足),提出了一种两阶段训练框架,将Qwen2.5-3B大语言模型适配于藏语场景: 持续预训练(CPT)阶段:使用20万条藏语单语语料(涵盖新闻、文学、宗教文本等多体裁),以自回归语言…

2026/11/14 17:23:54 阅读更多 →
2026世界机器人大会现场直击:人形机器人从“秀肌肉”走向“干实事”

2026世界机器人大会现场直击:人形机器人从“秀肌肉”走向“干实事”

摘要:本文以2026世界机器人大会为背景,从现场记者视角出发,介绍了银河通用Galbot ET1、魔法原子MagicBot D1等明星产品,深入剖析了人形机器人在运动控制、灵巧操作、成本三方面的技术难点与突破,并展望了其在工厂、仓库…

2026/11/1 23:00:21 阅读更多 →
云、云计算、云服务知识点及具体实例

云、云计算、云服务知识点及具体实例

一、公有云、私有云、云服务、云计算知识点 1、概念 一、云服务与云计算 云服务:是基于互联网的相关服务的增加、使用和交互模式,通过网络以按需、易扩展的方式获得虚拟化资源,计算能力可作为商品通过互联网流通,像水电一样按需取…

2026/10/25 8:03:09 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/14 5:13:29 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/14 5:13:29 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/14 5:13:29 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/13 22:08:41 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/14 2:41:37 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/14 5:13:29 阅读更多 →

日新闻

周新闻

月新闻