如何防止JavaScript中的正则表达式回溯

 更新时间:2023年08月15日 10:08:56   作者:dralexsanderl  
某些正则表达式模式可能容易受到回溯的影响,这可能会导致超线性运行时,并可能导致DoS攻击,本文就来介绍一下如何防止JavaScript中的正则表达式回溯,感兴趣的可以了解一下

正则表达式是用于在软件应用程序中操作和验证文本的强大工具。然而,某些正则表达式模式可能容易受到回溯的影响,这可能会导致超线性运行时,并可能导致DoS攻击。在本文中,我们将探讨什么是回溯、它如何导致性能问题以及如何在正则表达式中防止回溯。

正则表达式中的回溯是什么

回溯是正则表达式引擎用来处理包含可选或重复子模式的复杂模式的技术。当正则表达式模式包含可选或重复的子模式时,引擎可能需要尝试子模式的多种组合才能找到匹配项。这个过程称为回溯。

例如,有以下正则表达式:

/^[a-zA-Z0-9\s]+$/

此正则表达式应匹配仅包含字母数字字符和空格的任何字符串。然而,它很容易受到回溯的影响,因为+字符类后面的运算符允许字符类的任意数量的重复。

攻击者可以通过发送包含一长串不匹配字符的恶意搜索查询来利用此漏洞,例如:

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaab

该字符串包含 30 个a字符,后跟一个b. 当正则表达式引擎尝试匹配该字符串时,它将前 30 个a字符与字符类匹配,但无法匹配b字符。然后,引擎将回溯并尝试字符类的不同组合,直到匹配整个字符串或耗尽所有可能的组合。

在本例中,字符串中有 31 个字符,因此有 2 种可能的字符类组合可供尝试。这可能需要很长的时间,可能会导致服务器遭受 DoS 攻击。

为了防止此漏洞,您可以修改正则表达式以使用*运算符代替+运算符,如下所示:

/^[a-zA-Z0-9\s]*$/

使用*可以使正则表达式不易受到回溯并降低 DoS 攻击的风险,因为它减少了正则表达式引擎需要探索的可能路径的数量。

+的意思是“一个或多个”,而*的意思是“零个或多个”。使用+时,正则表达式引擎必须在放弃之前尝试与模式匹配的所有可能的字符组合。这可能会导致回溯并导致引擎花费过多的时间来尝试匹配字符串,从而更容易受到 DoS 攻击。

另一方面,使用*使子模式成为可选,这意味着如果不匹配,正则表达式引擎可以完全跳过它。这减少了引擎需要探索的可能路径的数量。

回溯如何导致性能问题

回溯可能会通过两种方式导致性能问题:

  • 超线性运行时间:回溯可能会导致正则表达式模式的运行时间变得超线性,这意味着匹配模式所需的时间增长速度快于输入字符串的长度。这可能会使该模式对于长输入字符串极其缓慢,并且如果将该模式应用于不受信任的用户输入,则可能会导致 DoS 攻击。
  • 高内存使用量:回溯还会导致正则表达式引擎使用大量内存,特别是当模式包含嵌套的可选或重复的子模式时。这可能会导致应用程序内存不足并崩溃。

如何防止正则表达式模式中的回溯

为了防止正则表达式模式中的回溯,我们需要以避免可选或重复子模式的方式设计思路。以下是我们可以使用的一些技巧:

使用特定的字符类:

使用特定的字符类可以通过限制可以匹配子模式的字符数来帮助防止回溯。例如,/[a-z]/匹配从 a 到 z 的任何小写字母。

使用非捕获组

使用非捕获组可以通过避免不必要的内存分配来帮助防止回溯。例如,/(?:ab)+/匹配字符串ab的一次或多次出现,而不创建捕获组。

使用原子组

使用原子组可以通过使子模式成为非可选来帮助防止回溯。例如,/a(?>b|c)/匹配包含字母a后跟bc的字符串,而不进行回溯。

使用多个子模式而不将其中任何一个设为可选

使用多个子模式而不将其中任何一个设为可选可以通过限制正则表达式引擎需要探索的可能路径的数量来帮助防止回溯。例如,/^(ab|cd|ef)$/匹配abcdef字符串,而不进行回溯。

使用所有格子模式:

使用所有格子模式可以通过使子模式成为非可选来帮助防止回溯。所有格子模式由语法(?+...)表示。例如,/a(?+b)/匹配包含字母a后跟字母b的字符串,而不进行回溯。

使用惰性量词:

使用惰性量词可以通过使子模式可选来帮助防止回溯,但仍然可以防止回溯。惰性量词由+?or*?符号表示。例如,/a+?/匹配一​​次或多次出现的字母a,但使用惰性量词来防止回溯。

使用有界量词:

使用有界量词可以通过限制子模式的重复次数来帮助防止回溯。有界量词由语法{min,max}表示,其中minmax是指定最小和最大重复次数的整数。例如,/a{1,3}/匹配包含重复一到三次的字母a的字符串,而不回溯。

到此这篇关于如何防止JavaScript中的正则表达式回溯的文章就介绍到这了,更多相关JavaScript 正则表达式回溯内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 在JavaScript中让this保持正确的指向的解决方案

    在JavaScript中让this保持正确的指向的解决方案

    这篇文章主要介绍了关于在 JavaScript 中如何让 this 保持正确的指向的解决方案,文中给大家介绍了三种解决方案,使用闭包,使用箭头函数和换绑 this这三种方法,文中有详细的代码示例供大家参考,需要的朋友可以参考下
    2024-01-01
  • JavaScript实现伸缩二级菜单

    JavaScript实现伸缩二级菜单

    这篇文章主要为大家详细介绍了JavaScript实现伸缩二级菜单,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-10-10
  • JavaScript实现的简单烟花特效代码

    JavaScript实现的简单烟花特效代码

    这篇文章主要介绍了JavaScript实现的简单烟花特效代码,涉及JavaScript数学运算及页面元素基于定时函数运动的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-10-10
  • iframe的父子窗口之间的对象相互调用基本用法

    iframe的父子窗口之间的对象相互调用基本用法

    iframe在使用时可能会涉及到父子窗口之间传值和方法的相互调用,研究了一下其实非常简单,就那么几个用法而已,在此与大家分享下,感兴趣的朋友可以参考下
    2013-09-09
  • javascript实现继承的简单实例

    javascript实现继承的简单实例

    这篇文章主要介绍了javascript实现继承的简单实例的相关资料,需要的朋友可以参考下
    2015-07-07
  • js判断浏览器的环境(pc端,移动端,还是微信浏览器)

    js判断浏览器的环境(pc端,移动端,还是微信浏览器)

    这篇文章主要介绍了js判断浏览器的环境(pc端,移动端,还是微信浏览器),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-01-01
  • JavaScript实现点赞功能的示例

    JavaScript实现点赞功能的示例

    本文主要介绍了JavaScript实现点赞功能的示例,分享给大家
    2014-04-04
  • JavaScript读取本地文件常用方法流程解析

    JavaScript读取本地文件常用方法流程解析

    这篇文章主要介绍了JavaScript读取本地文件常用方法流程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • 前端实现图片或视频预览的三种方法总结

    前端实现图片或视频预览的三种方法总结

    在JavaScript中实现前端图片上传即时预览功能是一项常见的需求,特别是在网页交互设计中,这篇文章主要给大家介绍了关于前端实现图片或视频预览的三种方法,需要的朋友可以参考下
    2024-06-06
  • JavaScript实现千位分隔符几种常见方法

    JavaScript实现千位分隔符几种常见方法

    将普通的数字转换为带千位分隔符格式的数字字符串是一个非常常见的问题,这篇文章主要介绍了JavaScript实现千位分隔符的几种常见方法,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-09-09

最新评论