fastjson篇1-基础用法
Fastjson 是 Alibaba 开发的 Java 语言编写的高性能 JSON 库,用于将数据在 JSON 和 Java Object 之间互相转换。
两个接口:
JSON.toJSONString
将 Java 对象转换为 json 对象,序列化的过程。JSON.parseObject/JSON.parse
将 json 对象重新变回 Java 对象;反序列化的过程
poe.xml1
2
3
4
5
6
7
8
9
10<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.24</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
先定义一个Student类,方便后面使用: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
37import java.util.Properties;
public class Student {
public String name;
private int age;
private String address;
private Properties properties;
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 String getAddress() {
System.out.println("getAddress");
return address;
}
public Properties getProperties() {
System.out.println("getProperties");
return properties;
}
}
几个参数:
SerializerFeature.WriteClassName
JSON.toJSONString()中的一个设置属性值,设置之后在序列化的时候会多写入一个@type,即写上被序列化的类名,type可以指定反序列化的类,并且调用其getter/setter/is方法
Feature.SupportNonPublicField
如果需要还原出private属性的话,还需要在JSON.parseObject/JSON.parse中加上Feature.SupportNonPublicField参数
test:
需要先在Student类里加个setAge方法来测试,测完注释掉1
2
3
4
5
6
7
8
9
10
11
12import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
public class test {
public static void main(String[] args) {
Student student=new Student();
student.setName("jmx0hxq");
student.setAge(19);
System.out.println(JSON.toJSONString(student, SerializerFeature.WriteClassName));
}
}
输出1
2
3
4
5
6
7
8
9构造函数
setName
setAge
getAddress
getAge
getName
getProperties
{"@type":"Student","age":19,"name":"jmx0hxq"}
还原private属性
1 | import com.alibaba.fastjson.JSON; |
输出1
2
3
4
5
6
7
8
9
10构造函数
setName
Student@4b9af9a9
Student
getAddress
china
getAge
19
getName
jmx0hxq
如果不加Feature.SupportNonPublicField属性,则无法得到私有属性结果就是:1
Object obj = JSON.parseObject(jsonString, Student.class);
1 | 构造函数 |
如果不加Student.class,则无法成功反序列化为Student类,而是JSONObject类:1
Object obj = JSON.parseObject(jsonString);
1 | getAddress |
结论
当反序列化为
JSON.parseObject(*)
形式,即未指定class时,会调用反序列化得到的类的构造函数、所有属性的getter方法、JSON里面的非私有属性的setter方法(==这里是因为private属性的变量不应该有set方法,如果自己加个set方法可以发现是会调用的,如果调用了自己设置的set方法,那反序列化的时候即使不加Feature.SupportNonPublicField也能得到它的值==),其中properties属性的getter方法会被调用两次当反序列化为
JSON.parseObject(*,*.class)
形式即指定class时,只调用反序列化得到的类的构造函数、JSON里面的非私有属性的setter方法(==这里是因为private属性的变量不应该有set方法,如果自己加个set方法可以发现是会调用的,如果调用了自己设置的set方法,那反序列化的时候即使不加Feature.SupportNonPublicField也能得到它的值==)、properties属性的getter方法;当反序列化为
JSON.parseObject(*)
形式即未指定class进行反序列化时得到的都是JSONObject类对象,而只要指定了class即JSON.parseObject(*,*.class)
形式得到的都是特定的Student类;
parse和parseObject的区别
主要的区别就是parseObject()
返回的是JSONObject,而parse()
返回的是实际类型的对象
上面的代码我们直接Object obj = JSON.parse(jsonString);
就可以得到Object obj = JSON.parseObject(jsonString, Student.class);
一样的结果
这里参考drun1baby师傅的博客解释:
parseObject()
会额外的将Java对象转为 JSONObject对象,即JSON.toJSON()
。所以进行反序列化时的细节区别在于,parse()
会识别并调用目标类的setter
方法及某些特定条件的getter
方法,而parseObject()
由于多执行了JSON.toJSON(obj)
,所以在处理过程中会调用反序列化目标类的所有setter
和getter
方法。
漏洞原理
fastjson 在反序列化的时候会去找我们在 @type
中规定的类是哪个类,然后在反序列化的时候会自动调用这些 setter 与 getter 方法和构造函数的调用1
2
3
4
5
6
7
8
9满足条件的setter:
- 非静态函数
- 返回类型为void或当前类
- 参数个数为1个
满足条件的getter:
- 非静态方法
- 无参数
- 返回值类型继承自Collection或Map或AtomicBoolean或AtomicInteger或AtomicLong
如果这些函数有危险函数则可以造成漏洞