为什么火狐浏览器在执行大量复杂正则匹配的JS脚本时会导致主线程资源死锁?

梦浩大大_3028

梦浩大大_3028

2026-06-08

1014人浏览

原创

火狐浏览器因nfa正则引擎指数级回溯及单线程阻塞导致页面冻结;根本原因是嵌套量词等引发千万级回溯,叠加翻译类扩展注入的未优化正则,且firefox不支持占有量词;需通过禁用扩展、web worker隔离、锚定正则等防护。

为什么火狐浏览器在执行大量复杂正则匹配的js脚本时会导致主线程资源死锁?

火狐浏览器在执行大量复杂正则匹配的JS脚本时,主线程会持续占用CPU并无法响应用户操作,页面冻结、右键失灵、滚动卡住,甚至触发“脚本运行时间过长”警告,本质是单线程事件循环被阻塞,而非内存或网络问题。

根本原因:NFA引擎指数级回溯 + 单线程无隔离

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%时间轴,且无空闲间隙;

Feishu calendar sync, local ics to json data for AI agent
Feishu calendar sync, local ics to json data for AI agent

将ICS日历文件转为JSON格式,用于飞书日历导入导出及数据集成。

下载

第四步:禁用所有含“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——超过即高危,必须重构。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

火狐浏览器 js 浏览器

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

2023.06.20

4136

8

js获取当前时间
js获取当前时间

JS全称JavaScript,是一种具有函数优先的轻量级,解释型或即时编译型的编程语言;它是一种属于网络的高级脚本语言,主要用于Web,常用来为网页添加各式各样的动态功能。js怎么获取当前时间呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.07.28

1295

5

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.03

1658

5

js是什么意思
js是什么意思

JS是JavaScript的缩写,它是一种广泛应用于网页开发的脚本语言。JavaScript是一种解释性的、基于对象和事件驱动的编程语言,通常用于为网页增加交互性和动态性。它可以在网页上实现复杂的功能和效果,如表单验证、页面元素操作、动画效果、数据交互等。

2023.08.17

9663

11

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

2023.09.01

920

4

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.04

2504

5

Js中concat和push的区别
Js中concat和push的区别

Js中concat和push的区别:1、concat用于将两个或多个数组合并成一个新数组,并返回这个新数组,而push用于向数组的末尾添加一个或多个元素,并返回修改后的数组的新长度;2、concat不会修改原始数组,是创建新的数组,而push会修改原数组,将新元素添加到原数组的末尾等等。本专题为大家提供concat和push相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.14

1509

5

js截取字符串的方法介绍
js截取字符串的方法介绍

JavaScript字符串截取方法,包括substring、slice、substr、charAt和split方法。这些方法可以根据具体需求,灵活地截取字符串的不同部分。在实际开发中,根据具体情况选择合适的方法进行字符串截取,能够提高代码的效率和可读性 。

2023.09.21

4289

3

js生成随机数方法
js生成随机数方法

JavaScript生成随机数的方法,包括使用Math.random()方法生成指定范围内的随机整数、生成随机字符串和生成随机颜色。根据具体需求,可以选择适合的方法来生成随机数,以实现各种功能 。

2023.09.25

2455

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
JavaScript正则表达式基础与实战
JavaScript正则表达式基础与实战

共11课时 | 1.7万人学习

WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 20.9万人学习