浅析ReDoS的原理与实践
转载于http://www.freebuf.com/articles/network/124422.html
ReDoS(Regular expression Denial of Service)
正则表达式拒绝服务攻击。开发人员使用了正则表达式来对用户输入的数据进行有效性校验, 当编写校验的正则表达式存在缺陷或者不严谨时, 攻击者可以构造特殊的字符串来大量消耗服务器的系统资源,造成服务器的服务中断或停止。
1 常见术语
先让我们来了解几个概念:
1.1 Regex
正则表达式(Regular Expression, Regex
)是由字符(可为英文字母、数字、符号等
)与元字符(特殊符号
)组成的一种有特定规则的特殊字符串。在模式匹配中,正则表达式通常被用于验证邮箱、URL、手机号码等。
常用元字符:
元字符 | 说明 |
---|---|
\ | 将下一个字符标记为一个特殊字符、或一个原义字符、或一个向后引用、或一个八进制转义符。例如,“n ” 匹配字符 “n ”。“\n ” 匹配一个换行符。序列 “\\ ” 匹配 “\ ” 而 “\( ” 则匹配 “( ”。 |
^ | 匹配输入字符串的开始位置。如果设置了RegExp对象的Multiline属性,^ 也匹配 “\n ” 或 “\r ” 之后的位置。 |
$ | 匹配输入字符串的结束位置。如果设置了RegExp对象的Multiline属性,$ 也匹配 “\n ” 或 “\r ” 之前的位置。 |
* | 匹配前面的子表达式零次或多次。例如,zo* 能匹配 “z ”、“zo ” 以及 “zoo ”。* 等价于 {0,} 。 |
+ | 匹配前面的子表达式一次或多次。例如,“zo+ ” 能匹配 “zo ” 以及 “zoo ”,但不能匹配 “z ”。+ 等价于{1,} 。 |
? | 匹配前面的子表达式零次或一次。例如,“do(es)? ” 可以匹配 “do ” 或 “does ” 中的 “do ”。? 等价于{0,1} 。 |
. | 匹配除 “\n ” 之外的任何单个字符。要匹配包括 “\n ” 在内的任何字符,请使用像 “ (.\$\lambda_1$\n) ” 的模式。 |
(pattern) | 匹配pattern并获取这一匹配的子字符串。该子字符串用于向后引用。所获取的匹配可以从产生的Matches集合得到,在VBScript中使用SubMatches集合,在JScript中则使用$0…$9属性。要匹配圆括号字符,请使用 “\( ” 或 “\) ”。 |
\w | 匹配包括下划线的任何单词字符。等价于 “[A-Za-z0-9_] ”。 |
\W | 匹配任何非单词字符。等价于 “[^A-Za-z0-9_] ”。 |
更多元字符请参考: 维基百科
1.2 DoS & DDoS
拒绝服务攻击(Denial-of-Service Attack
)亦称洪水攻击,是一种网络攻击手法,其目的在于使目标电脑的网络或系统资源耗尽,使服务暂时中断或停止,导致其正常用户无法访问。
分布式拒绝服务攻击(Distributed Denial-of-Service Attack
),是使用网络上两个或两个以上被攻陷的电脑作为 “僵尸
” 向特定的目标发动 “拒绝服务
” 式攻击。
DDoS攻击可以具体分成两种形式:
- 带宽消耗型攻击
- 洪水攻击
UDP、ICMP、ping of death
- 放大攻击
NTP、DNS
- 洪水攻击
- 资源消耗型攻击
SYN洪水、LAND attack、CC
1.3 FSM、DFA、 NFA
有限状态自动机:(FSM “finite state machine” 或者FSA “finite
state automaton”
)是为研究有限内存的计算过程和某些语言类而抽象出的一种计算模型。有限状态自动机拥有有限数量的状态,每个状态可以迁移到零个或多个状态,输入字串决定执行哪个状态的迁移。
有限状态自动机还可以分成确定与非确定两种, 非确定有限状态自动机可以转化为确定有限状态自动机。
正则表达式引擎分成两类:一类称为DFA(确定性有限状态自动机)
,另一类称为NFA(非确定性有限状态自动机)
。两类引擎要顺利工作,都必须有一个正则式和一个文本串,一个捏在手里,一个吃下去。DFA
捏着文本串去比较正则式,看到一个子正则式,就把可能的匹配串全标注出来,然后再看正则式的下一个部分,根据新的匹配结果更新标注。而NFA
是捏着正则式去比文本,吃掉一个字符,就把它跟正则式比较,匹配就记下来:“某年某月某日在某处匹配上了!”,然后接着往下干。一旦不匹配,就把刚吃的这个字符吐出来,一个个的吐,直到回到上一次匹配的地方。
部分程序及其所使用的正则引擎:
引擎类型 | 程序 |
---|---|
DFA | awk(大多数版本)、egrep(大多数版本)、flex、lex、MySQL、Procmail |
传统型 NFA | GNU Emacs、Java、grep(大多数版本)、less、more、.NET语言、PCRE library、Perl、PHP(所有三套正则库)、Python、Ruby、set(大多数版本)、vi |
POSIX NFA | mawk、Mortice Lern System’s utilities、GUN Emacs(明确指定时使用) |
DFA/NFA混合 | GNU awk、 GNU grep/egrep、 Tcl |
2 ReDoS 原理
2.1 概述
DFA
对于文本串里的每一个字符只需扫描一次,比较快,但特性较少;NFA
要翻来覆去吃字符、吐字符,速度慢,但是特性(如:分组、替换、分割)丰富。NFA
支持 惰性(lazy)
、回溯(backtracking)
、反向引用(backreference)
,NFA
缺省应用greedy
模式,NFA
可能会陷入递归险境导致性能极差。
2.2 说明
我们定义一个正则表达式^(a+)+$
来对字符串aaaaX
匹配。使用NFA
的正则引擎,必须经历2^4=16
次尝试失败后才能否定这个匹配。同理字符串为aaaaaaaaaaX
就要经历2^10=1024
次尝试。如果我们继续增加a
的个数为20个、30个或者更多,那么这里的匹配会变成指数增长。
下面我们以python
语言为例子来进行代码的演示:
#!/usr/bin/env python
# coding: utf-8
import re
import time
def exp(target_str):
"""
"""
s1 = time.time()
flaw_regex = re.compile('^(a+)+$')
flaw_regex.match(target_str)
s2 = time.time()
print("Consuming time: %.4f" % (s2-s1))
if __name__ == '__main__':
str_list = (
'aaaaaaaaaaaaaaaaX', # 2^16
'aaaaaaaaaaaaaaaaaaX', # 2^18
'aaaaaaaaaaaaaaaaaaaaX', # 2^20
'aaaaaaaaaaaaaaaaaaaaaaX', # 2^22
'aaaaaaaaaaaaaaaaaaaaaaaaX', # 2^24
'aaaaaaaaaaaaaaaaaaaaaaaaaaX', # 2^26
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaX', # 2^36
)
for evil_str in str_list:
print('Current: %s' % evil_str)
exp(evil_str)
print('--'*40)
把上面的代码保存成redos.py
文件并执行这个 py 脚本文件:
$ python redos.py
Current: aaaaaaaaaaaaaaaaX
Consuming time: 0.0043
--------------------------------------------------------------------------------
Current: aaaaaaaaaaaaaaaaaaX
Consuming time: 0.0175
--------------------------------------------------------------------------------
Current: aaaaaaaaaaaaaaaaaaaaX
Consuming time: 0.0678
--------------------------------------------------------------------------------
Current: aaaaaaaaaaaaaaaaaaaaaaX
Consuming time: 0.2370
--------------------------------------------------------------------------------
Current: aaaaaaaaaaaaaaaaaaaaaaaaX
Consuming time: 0.9842
--------------------------------------------------------------------------------
Current: aaaaaaaaaaaaaaaaaaaaaaaaaaX
Consuming time: 4.1069
--------------------------------------------------------------------------------
Current: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaX
输出到最后一行貌似程序卡住了,我们来看下电脑的 CPU:
CPU利用率已经快接近100%了,我们在分别执行两次(电脑配置低的慎重操作):
2.3 总结
每个恶意的正则表达式模式应该包含:
- 使用重复分组构造
- 在重复组内会出现
- 重复
- 交替重叠
有缺陷的正则表达式会包含如下部分:
(a+)+
([a-zA-Z]+)*
(a|aa)+
(a|a?)+
(.*a){x} | for x > 10
注意: 这里的a
是个泛指
2.4 实例
下面我们来展示一些实际业务场景中会用到的缺陷正则。
英文的个人名字:
- Regex:
^[a-zA-Z]+(([\'\,\.\-][a-zA-Z ])?[a-zA-Z]*)*$
- Payload:
aaaaaaaaaaaaaaaaaaaaaaaaaaaa!
- Regex:
Java Classname
- Regex:
^(([a-z])+.)+[A-Z]([a-z])+$
- Payload:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!
- Regex:
Email格式验证
- Regex:
^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@(([0-9a-zA-Z])+([-\w]*[0-9a-zA-Z])*\.)+[a-zA-Z]{2,9})$
- Payload:
a@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!
- Regex:
多个邮箱地址验证
- Regex:
^[a-zA-Z]+(([\'\,\.\-][a-zA-Z ])?[a-zA-Z]*)*\s+<(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3})>$|^(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3})$
- Payload:
aaaaaaaaaaaaaaaaaaaaaaaa!
- Regex:
复数验证
- Regex:
^\d*[0-9](|.\d*[0-9]|)*$
- Payload:
1111111111111111111111111!
- Regex:
模式匹配
- Regex:
^([a-z0-9]+([\-a-z0-9]*[a-z0-9]+)?\.){0,}([a-z0-9]+([\-a-z0-9]*[a-z0-9]+)?){1,63}(\.[a-z0-9]{2,7})+$
- Payload:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!
- Regex:
使用python
来进行测试有缺陷的正则示例:
$ python -c "import re;re.match('^[a-zA-Z]+(([\'\,\.\-][a-zA-Z ])?[a-zA-Z]*)*$', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaa!')"
3 ReDoS 防范
哪里会用到Regex
, 几乎在我们的网络程序与设备资源的任何位置都会用到。如: WAF
、Web前端
、Web后端
、DB数据库
等。
3.1 常见位置
客户端
- 浏览器
- 移动设备
服务器端
3.2 防范手段
防范手段只是为了降低风险而不能百分百消除 ReDoS
这种威胁。当然为了避免这种威胁的最好手段是尽量减少正则在业务中的使用场景或者多做测试, 增加服务器的性能监控等。
- 降低正则表达式的复杂度, 尽量少用分组
- 严格限制用户输入的字符串长度(特定情况下)
- 使用单元测试、fuzzing 测试保证安全
- 使用静态代码分析工具, 如: sonar
- 添加服务器性能监控系统, 如: zabbix
2.5 参考链接
《精通正则表达式》
http://blog.csdn.net/c601097836/article/details/47040703
http://hooopo.iteye.com/blog/548087
http://www.guoziweb.com/archive/1160.html
https://swtch.com/~rsc/regexp/regexp1.html
https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS
https://en.wikipedia.org/wiki/ReDoS
https://www.checkmarx.com/wp-content/uploads/2015/03/ReDoS-Attacks.pdf
https://www.exploit-db.com/docs/38149.pdf
https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS
https://www.owasp.org/images/3/38/20091210_VAC-REGEX_DOS-Adar_Weidman.pdf
https://www.owasp.org/index.php/OWASP_Validation_Regex_Repository
浅析ReDoS的原理与实践的更多相关文章
- 搞懂分布式技术10:LVS实现负载均衡的原理与实践
搞懂分布式技术10:LVS实现负载均衡的原理与实践 浅析负载均衡及LVS实现 原创: fireflyc 写程序的康德 2017-09-19 负载均衡 负载均衡(Load Balance,缩写LB)是一 ...
- Atitit 管理原理与实践attilax总结
Atitit 管理原理与实践attilax总结 1. 管理学分类1 2. 我要学的管理学科2 3. 管理学原理2 4. 管理心理学2 5. 现代管理理论与方法2 6. <领导科学与艺术4 7. ...
- Atitit.ide技术原理与实践attilax总结
Atitit.ide技术原理与实践attilax总结 1.1. 语法着色1 1.2. 智能提示1 1.3. 类成员outline..func list1 1.4. 类型推导(type inferenc ...
- Atitit.异步编程技术原理与实践attilax总结
Atitit.异步编程技术原理与实践attilax总结 1. 俩种实现模式 类库方式,以及语言方式,java futuretask ,c# await1 2. 事件(中断)机制1 3. Await 模 ...
- Atitit.软件兼容性原理与实践 v5 qa2.docx
Atitit.软件兼容性原理与实践 v5 qa2.docx 1. Keyword2 2. 提升兼容性的原则2 2.1. What 与how 分离2 2.2. 老人老办法,新人新办法,只新增,少修改 ...
- Atitit 表达式原理 语法分析 原理与实践 解析java的dsl 递归下降是现阶段主流的语法分析方法
Atitit 表达式原理 语法分析 原理与实践 解析java的dsl 递归下降是现阶段主流的语法分析方法 于是我们可以把上面的语法改写成如下形式:1 合并前缀1 语法分析有自上而下和自下而上两种分析 ...
- Atitit.gui api自动化调用技术原理与实践
Atitit.gui api自动化调用技术原理与实践 gui接口实现分类(h5,win gui, paint opengl,,swing,,.net winform,)1 Solu cate1 Sol ...
- Atitit.提升语言可读性原理与实践
Atitit.提升语言可读性原理与实践 表1-1 语言评价标准和影响它们的语言特性1 1.3.1.2 正交性2 1.3.2.2 对抽象的支持3 1.3.2.3 表达性3 .6 语言设计中的权 ...
- Atitit 网络爬虫与数据采集器的原理与实践attilax著 v2
Atitit 网络爬虫与数据采集器的原理与实践attilax著 v2 1. 数据采集1 1.1. http lib1 1.2. HTML Parsers,1 1.3. 第8章 web爬取199 1 2 ...
随机推荐
- shell循环之跳出循环
1.break break命令允许跳出所有循环(终止执行后面的所有循环). 下面的例子中,脚本进入死循环直至用户输入数字大于5.要跳出这个循环,返回到shell提示符下,需要使用break命令. #! ...
- Linu常用日志分析实战
日志结构分析 分析日志状态码所在位置为第九个 遍历取出第一行日志的每个字段 //取出第一行日志 awk 'NR==1{for(i=1;i<=NF;i++)print i"= " ...
- Linux proc文件系统小记
序言: 当linux系统存在多个网口时(也可以是一个网口配置两个IP),每个网口配置不同的IP地址,并且分别连接到不同的电脑上,电脑分别配置与相连的网口统一网段的IP且将电脑网关设置为linux的网口 ...
- Element 对话框简单使用
官方文档介绍的是页内对话框,但没有基于组件的对话框,这里记录一下,原理就是父子传值是否显示 父页导入组件 <template> <div class="home" ...
- Webpack:打包项目报错(eslint: debugger)
打包项目需要把项目中的debugger删除,否则会报错.
- 取消input默认提示框
input输入框有自动保存记忆功能,点击的时候之前输入的内容会在下拉框自动提示 autocomplete="off",这是H5的一个属性. <input type=" ...
- JAVA安全基础之代理模式(二)
JAVA安全基础之代理模式(二) 上篇讲到静态代理模式,这时候我们发现,一个代理类只能为一个类服务,如果需要代理的类很多,那么就需要编写大量的代理类,比较繁琐.所以就有了动态代理 动态代理 动态代理的 ...
- React项目中应用TypeScript
一.前言 单独的使用typescript 并不会导致学习成本很高,但是绝大部分前端开发者的项目都是依赖于框架的 例如和vue.react 这些框架结合使用的时候,会有一定的门槛 使用 TypeScri ...
- wpf 多表头
WPF多表头技术探索总结 方案一:Grid+TextBlock嵌套DataGrid方式. 该方案是现在项目中已使用的方案.实现起来比较简单,但不具有通用性,不同数据DataGrid需要指定不同的Tex ...
- 洛谷P1781——宇宙总统(高精度排序)
题目描述 地球历公元6036年,全宇宙准备竞选一个最贤能的人当总统,共有n个非凡拔尖的人竟选总统,现在票数已经统计完毕,请你算出谁能够当上总统. 输入输出格式 输入格式: 第一行为一个整数n,代表竞选 ...