无题
Jackson 的核心模块由三部分组成。
- jackson-core,核心包,提供基于"流模式"解析的相关 API,它包括 JsonPaser 和 JsonGenerator。 Jackson 内部实现正是通过高性能的流模式 API 的 JsonGenerator 和 JsonParser 来生成和解析 json。
- jackson-annotations,注解包,提供标准注解功能;
- jackson-databind ,数据绑定包, 提供基于"对象绑定" 解析的相关 API ( ObjectMapper ) 和"树模型" 解析的相关 API (JsonNode);基于"对象绑定" 解析的 API 和"树模型"解析的 API 依赖基于"流模式"解析的 API。
<dependencies> |
ObjectMapper
Jackson 最常用的 API 就是基于"对象绑定" 的 ObjectMapper:
- ObjectMapper可以从字符串,流或文件中解析JSON,并创建表示已解析的JSON的Java对象。 将JSON解析为Java对象也称为从JSON反序列化Java对象。
- ObjectMapper也可以从Java对象创建JSON。 从Java对象生成JSON也称为将Java对象序列化为JSON。
- Object映射器可以将JSON解析为自定义的类的对象,也可以解析置JSON树模型的对象。
之所以称为ObjectMapper是因为它将JSON映射到Java对象(反序列化),或者将Java对象映射到JSON(序列化)。
import com.fasterxml.jackson.databind.ObjectMapper; |
将对象转化为json
- writeValue()
- writeValueAsString()
- writeValueAsBytes()
import com.fasterxml.jackson.databind.ObjectMapper; |
JsonParser
Jackson JsonParser类是一个底层一些的JSON解析器。 它类似于XML的Java StAX解析器,差别是JsonParser解析JSON而不解析XML。
Jackson JsonParser的运行层级低于Jackson ObjectMapper。 这使得JsonParser比ObjectMapper更快,但使用起来也比较麻烦。
使用JsonParser需要先创建一个JsonFactory
import com.fasterxml.jackson.core.JsonFactory; |
一旦创建了Jackson JsonParser,就可以使用它来解析JSON。 JsonParser的工作方式是将JSON分解为一系列令牌,可以一个一个地迭代令牌。
这是一个JsonParser示例,它简单地循环遍历所有标记并将它们输出到System.out。 这是一个实际上很少用示例,只是展示了将JSON分解成的令牌,以及如何遍历令牌的基础知识。
可以使用JsonParser的nextToken()获得一个JsonToken。 可以使用此JsonToken实例检查给定的令牌。 令牌类型由JsonToken类中的一组常量表示。 这些常量是
import com.fasterxml.jackson.core.JsonFactory; |
使用equals方法 检查如果标记的字段名称是相同的 就返回其值
指向的令牌是字符串字段值,则getValueAsString()返回当前令牌值作为字符串。 如果指向的令牌是整数字段值,则getValueAsInt()返回当前令牌值作为int值。 JsonParser具有更多类似的方法来获取不同类型的curren令牌值(例如boolean,short,long,float,double等)
JsonGenerator
Jackson JsonGenerator用于从Java对象(或代码从中生成JSON的任何数据结构)生成JSON。
同样的 使用JsonGenerator也需要先创建一个JsonFactory 从其中使用createGenerator() 来创建一个JsonGenerator
import com.fasterxml.jackson.core.*; |
多态问题
Java多态就是同一个接口使用不同的实例而执行不同的操作
在Jackson中 JacksonPolymorphicDeserialization可以解决这个问题 在反序列化某个类对象的过程中 如果类的成员不是具体类型 比如是Object 接口 或者 抽象类 那么可以在JSON字符串中 指定其类型 Jackson将生成具体类型的实例
具体来说就是 将具体的子类信息绑定在序列化的内容中 以便于后续反序列化的时候 直接得到目标子类对象 我们可以通过DefaultTyping 和 @JsonTypeInfo 注解来实现
DefaultTyping
四个值:
1 .JAVA_LANG_OBJECT
:当被序列化或反序列化的类里的属性被声明为一个Object类型时,会对该Object类型的属性进行序列化和反序列化,并且明确规定类名。(当然,这个Object本身也得是一个可被序列化的类)
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT);
输出
{"name":"fakes0u1","age":123,"object":["jackson.Hacker",{"skill":"moyu"}]} |
没设置的时候会输出
{"name":"fakes0u1","age":123,"object":{"skill":"moyu"}} |
OBJECT_AND_NON_CONCRETE
: 当类中有Interface AbstractClass
类时 对其进行序列化和反序列化 这也是enableDefaultTyping()
的默认选项
{"name":"fakes0u1","age":123,"object":["jackson.Hacker",{"skill":"moyu"}],"sex":["jackson.MySex",{"sex":0}]} |
看到接口也被成功的序列化和反序列化
NON_CONCRETE_AND_ARRAYS
:支持Arrays类型,可以在原来的test文件上直接修改
Hacker[] hacker = new Hacker[2]; |
NON_FINAL
:除了前面所有的特征外 包含即将被序列化的类里的全部、非final的属性将其进行序列化和反序列化
DefaultTyping类型 | 描述说明 |
---|---|
JAVA_LANG_OBJECT | 属性的类型为Object |
OBJECT_AND_NON_CONCRETE | 属性的类型为Object、Interface、AbstractClass |
NON_CONCRETE_AND_ARRAYS | 属性的类型为Object、Interface、AbstractClass、Array |
NON_FINAL | 所有除了声明为final之外的属性 |
@JsonTypeInfo注解
加上注释。
JsonTypeInfo.Id.NONE
:用于指定在序列化和反序列化过程中不包含任何类型标识 不使用识别码,输出没有什么不一样JsonTypeInfo.Id.CLASS
:反序列化的时候通过@class
指定相关类,使用完全限定类名做识别
{"name":"fakes0u1","age":123,"object":{"@class":"jackson.Hacker","skill":"moyu"}} |
- JsonTypeInfo.Id.MINIMAL_CLASS:和
JsonTypeInfo.Id.CLASS
差不多,只不过@class
变成了@c
。
{"name":"fakes0u1","age":123,"object":{"@c":"jackson.Hacker","skill":"moyu"}} |
- JsonTypeInfo.Id.NAME:多了
@type
,但是没法被反序列化利用。序列化的输出变为
{"name":"fakes0u1","age":123,"object":{"@type":"Hacker","skill":"moyu"}} |
多出一个@type 这里并没有像上面的CLASS一样 给出具体包名和类名 同时在反序列化的时候还会报错 也就是说 这个注释并不适用于反序列化过程
5. JsonTypeInfo.Id.CUSTOM:需要自定义,手写解析器。
所以JsonTypeInfo.Id.CLASS
和JsonTypeInfo.Id.MINIMAL_CLASS
可以触发反序列化漏洞。
Jackson反序列化漏洞
满足下面三个条件之一即存在Jackson反序列化漏洞:
- 调用了ObjectMapper.enableDefaultTyping()函数;
- 对要进行反序列化的类的属性使用了值为JsonTypeInfo.Id.CLASS的@JsonTypeInfo注解;
- 对要进行反序列化的类的属性使用了值为JsonTypeInfo.Id.MINIMAL_CLASS的@JsonTypeInfo注解;
如果反序列化的类的属性是Object
的时候,因为Object类型是任意类型的父类,因此扩大了我们的攻击面,我们只需要寻找出在目标服务端环境中存在的且构造函数或setter方法存在漏洞代码的类即可进行攻击利用
属性中没有Object
只能让他的构造函数或者是setter方法中存在危险函数
属性中有Object类
我们只需要在目标服务端中存在的且构造函数或setter方法存在漏洞的类即可进行攻击利用 例如 存在一个恶意类Evil 在其构造函数或者是setter方法中存在任意代码执行漏洞