THIS IS B3c0me

记录生活中的点点滴滴

0%

Fastjson

fastjson介绍

简介

FastJson是开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到Java Bean。Fastjson应用范围非常广,在github上star数超过22k。2017年3月15日,fastjson官方主动爆出fastjson在1.2.24及之前版本存在远程代码执行高危安全漏洞。攻击者可以通过此漏洞远程执行恶意代码来入侵服务器。2020年6月1日 fastjson爆发新的反序列化远程代码执行漏洞,fastjson 1.2.68及以前版本存在黑客利用漏洞,可绕过autoType限制,直接远程执行任意命令攻击服务器,风险极大。

漏洞成因

Fastjson组件在反序列化不可信数据时会导致远程代码执行。究其原因:

  • Fastjson 提供了反序列化功能,允许用户在输入 JSON 串时通过 “@type” 键对应的 value 指定任意反序列化类名

  • Fastjson 自定义的反序列化机制会使用反射生成上述指定类的实例化对象,并自动调用该对象的 setter 方法及部分 getter 方法。攻击者可以构造恶意请求,使目标应用的代码执行流程进入这部分特定 setter 或 getter 方法,若上述方法中有可被恶意利用的逻辑(也就是通常所指的 “Gadget” ),则会造成一些严重的安全问题。官方采用了黑名单方式对反序列化类名校验,但随着时间的推移及自动化漏洞挖掘能力的提升。新 Gadget 会不断涌现,黑名单这种治标不治本的方式只会导致不断被绕过,从而对使用该组件的用户带来不断升级版本的困扰

fastjson的基本使用

  • 引入依赖:在pom.xml里引入依赖即可

    1
    2
    3
    4
    5
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.40</version>
    </dependency>
  • 常用方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    Fastjson API入口类是com.alibaba.fastjson.JSON,常用的序列化操作都可以在JSON类上的静态方法直接完成。  
    public static final Object parse(String text); // 把JSON文本parse为JSONObject或者JSONArray
    public static final JSONObject parseObject(String text)// 把JSON文本parse成JSONObject
    public static final <T> T parseObject(String text, Class<T> clazz); // 把JSON文本parse为JavaBean
    public static final JSONArray parseArray(String text); // 把JSON文本parse成JSONArray
    public static final <T> List<T> parseArray(String text, Class<T> clazz); //把JSON文本parse成JavaBean集合
    public static final String toJSONString(Object object); // 将JavaBean序列化为JSON文本
    public static final String toJSONString(Object object, boolean prettyFormat); // 将JavaBean序列化为带格式的JSON文本
    public static final Object toJSON(Object javaObject); 将JavaBean转换为JSONObject或者JSONArray(和上面方法的区别是返回值是不一样的)

    1. 将对象序列化成json字符串

    String com.alibaba.fastjson.JSON.toJSONString(Object object)

    2. 将json字符串反序列化成对象

    <T> Project com.alibaba.fastjson.JSON.parseObject(String text, Class<T> clazz)

    3. 将json字符串反序列化成JSON对象

    JSONObject com.alibaba.fastjson.JSON.parseObject(String text)

    4.根据key 得到json中的json数组

    JSONArray com.alibaba.fastjson.JSONObject.getJSONArray(String key)

    5. 根据下标拿到json数组的json对象

    JSONObject com.alibaba.fastjson.JSONArray.getJSONObject(int index)

    6.. 根据key拿到json的字符串值

    String com.alibaba.fastjson.JSONObject.getString(String key)

    7. 根据key拿到json的int

    int com.alibaba.fastjson.JSONObject.getIntValue(String key)

    8. 根据key拿到json的boolean

    boolean com.alibaba.fastjson.JSONObject.getBooleanValue(String key)

POJO

POJO 是 Plain OrdinaryJava Object 的缩写,但是它通指没有使用 Entity Beans 的普通 java 对象,可以把 POJO 作为支持业务逻辑的协助类

Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package fastjson;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;

public class Student {
private String name;
private int age;

public Student() {
System.out.println("构造函数");
}

public String getName() {
System.out.println("getName");
return name;
}

public void setName(String name) {
System.out.println("setName");
this.name = name;
}

public int getAge() {
System.out.println("getAge");
return age;
}

public void setAge(int age) throws Exception{
System.out.println("setAge");
this.age = age;
}
public void setTest(int i){
System.out.println("setTest");
}
public static void test1() throws Exception {
Student student = new Student();
student.setAge(18);
student.setName("Sentiment");
System.out.println("====================");
String jsonString1 = JSON.toJSONString(student);
System.out.println("====================");
String jsonString2 = JSON.toJSONString(student, SerializerFeature.WriteClassName);
System.out.println(jsonString1);
System.out.println(jsonString2);
}
public static void test2()throws Exception{
String jsonString1 = "{\"age\":18,\"name\":\"Sentiment\"}\n";
String jsonString2 = "{\"@type\":\"fastjson.Student\",\"age\":18,\"name\":\"Sentiment\"}\n";
System.out.println(JSON.parse(jsonString1));
System.out.println("======================");
System.out.println(JSON.parse(jsonString2));
System.out.println("======================");
System.out.println(JSON.parseObject(jsonString1));
System.out.println("======================");
System.out.println(JSON.parseObject(jsonString2));
System.out.println("======================");
}
public static void main(String[] args) throws Exception {
test1();
//test2();
}
}

结果

1
2
3
4
5
6
7
8
9
10
11
构造函数
setAge
setName
====================
getAge
getName
====================
getAge
getName
{"age":18,"name":"Sentiment"}
{"@type":"fastjson.Student","age":18,"name":"Sentiment"}

test1

  • 调用JSON.toJSONString时会自动调用对应的getter

  • 若加上SerializerFeature.WriteClassName,则返回的内容除属性值外,还会加上@type字段指明类

test2

此时调用test2,将JSON字符串转换成对象

1
2
3
4
5
6
7
8
9
10
11
String jsonString1 = "{\"age\":18,\"name\":\"Sentiment\"}\n";
String jsonString2 = "{\"@type\":\"fastjson.Student\",\"age\":18,\"name\":\"Sentiment\"}\n";
System.out.println(JSON.parse(jsonString1));
System.out.println("======================");
System.out.println(JSON.parse(jsonString2));
System.out.println("======================");
System.out.println(JSON.parseObject(jsonString1));
System.out.println("======================");
System.out.println(JSON.parseObject(jsonString2));
System.out.println("======================");

结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{"name":"Sentiment","age":18}
======================
构造函数
setAge
setName
fastjson.Student@4629104a
======================
{"name":"Sentiment","age":18}
======================
构造函数
setAge
setName
getAge
getName
{"name":"Sentiment","age":18}
======================

可以看到:

当不加上@type指明类,是得不到类对象的

当对加上@type字段的字符串进行转换后,除了能得到类对象外,parse会调用对应的setterparseObject会调用settergetter

这种@type的方式也叫做autotype:

autotype 是 Fastjson 中的一个重要机制,粗略来说就是用于设置能否将 JSON 反序列化成对象。

漏洞

JdbcRowSetImpl链结合JNDI注入

适用版本:fastjson<1.2.24

参考:

1.https://blog.csdn.net/u012990687/article/details/110358442

2.http://t.csdn.cn/LfWLQ

欢迎关注我的其它发布渠道