火狐浏览器因NFA正则引擎指数级回溯及单线程阻塞导致页面冻结;根本原因是嵌套量词等引发千万级回溯,叠加翻译类扩展注入的未优化正则,且Firefox不支持占有量词;需通过禁用扩展、Web Worker隔离、锚定正则等防护。
火狐浏览器在执行大量复杂正则匹配的JS脚本时,主线程会持续占用CPU并无法响应用户操作,页面冻结、右键失灵、滚动卡住,甚至触发“脚本运行时间过长”警告,本质是单线程事件循环被阻塞,而非内存或网络问题。
JavaScript正则使用NFA(非确定性有限自动机)引擎,当正则表达式存在嵌套量词(如(a+)+)、模糊通配(如.*后接可能失败的子模式)或未锚定结构时,输入文本稍有不匹配,引擎就会反复试探所有可能的字符划分路径。输入长度每增加一位,回溯步数可能翻倍——100字符输入触发千万级尝试,而Firefox和Chrome一样运行在单线程主线程中,【一次匹配未完成,整个UI渲染、鼠标事件、定时器全部暂停】。
这与Node.js中ReDoS导致进程假死原理一致,但浏览器端更敏感:没有进程级重启机制,用户只能强制关闭标签页。
Firefox对第三方脚本注入更开放,大量翻译类扩展(如Immersive Translate、Mate Translate)会在页面加载后主动注入正则匹配逻辑,用于高亮双语段落、提取标题或替换术语。多个扩展同时运行时,各自注册的正则可能互相干扰——例如一个扩展匹配href="([^"]*)",另一个紧接着匹配title="([^"]*)",若HTML结构不标准(如缺少引号、属性换行),两个正则都会陷入长回溯,叠加效应使主线程锁死更快。
⚠️ 注意:Firefox当前版本(145)仍不支持占有量词(++、*+)和原子组((?>...))的原生语法,开发者无法用V8/SpiderMonkey通用方案直接堵死回溯入口,必须手动重写表达式。
第一步:打开卡死页面后立即按 Esc,中断可能正在执行的脚本;
第二步:右键→“检查元素”→切换到“控制台”,查看是否有 Maximum call stack size exceeded 或连续重复的 TypeError 报错;
第三步:在地址栏输入 about:performance,观察“Scripting”项是否长期占据100%时间轴,且无空闲间隙;
第四步:禁用所有含“translate”“词典”“查词”字样的扩展,刷新页面——若恢复响应,即可确认是多扩展正则叠加引发的死锁。
方法一:用 url.startsWith('/admin/') 替代 /^/admin/.*$/.test(url),零回溯、零风险;
方法二:路径参数提取改用 location.pathname.split('/').filter(Boolean) 得到干净数组,再按索引取值,彻底避开正则引擎;
方法三:对用户可控输入(如搜索框内容)做长度守门——if (input.length > 512) throw new Error('Input too long');,防止恶意超长字符串触发灾难性回溯。
① 所有Location路由正则必须锚定:^/api/users/d+(?:?[^#]*)?$,严禁出现 /api/users/.+ 这类未锚定写法;
② 禁用 .* 和 .+?,路径段统一用 [a-z0-9_-]+ 或 [^/]+ 替代;
③ 将高危正则匹配逻辑移入Web Worker:主线程只传URL和预编译正则对象,Worker内调用 test() 并设50ms硬性超时,超时即终止并返回默认路由;
④ 上线前用 regex101 开启 Debugger 模式,输入典型失败case(如 /a/b/c/d/e/f/g/xxx),观察步数是否突破1000——超过即高危,必须重构。