Java-Jackson反序列化漏洞及挖洞思路
使用Jackson反序列化遇到的问题及解决
使⽤Jackson反序列化遇到的问题及解决Jackson反序列化遇到的问题最近在项⽬中需要使⽤Jackson把前台转来的字符转为对象,转换过程中发⽣了错误,报错如下c om.fasterxml.jackson.databind.exc.InvalidFormatException: Can not construct instance of java.util.Date fromStringvalue '2018-09-14 15:12:08': not a valid representation (error: Failed to parse Date value '2018-09-14 15:12:08': Can not parse date "2018-09-14 15:12:08": not compatible with any of standard forms ("yyyy-MM-dd'T'HH:mm:ss.SSSZ","yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "EEE, dd MMM yyyy HH:mm:ss zzz", "yyyy-MM-dd"))原因是需要转换成的⽬标对象有Date类型的属性,前台传来的是yyyy-MM-dd HH:mm:ss类型⽽Jackson只⽀持以下四种yyyy-MM-dd'T'HH:mm:ss.SSSZyyyy-MM-dd'T'HH:mm:ss.SSS'Z'EEE, dd MMM yyyy HH:mm:ss zzzyyyy-MM-dd在⽹上查了许多⽅法都⽐较⿇烦,我太懒……发现⽤两个注解就可以轻松解决@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")private Date createTime;JackSon反序列化时忽略对象中不存在的json字段如果json字段⽐较多,⽽我们对象只需要部分字段,这时反序列化时会报错,可以在new ObjectMapper后加上objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);就可以在反序列化时忽略json中多余的字段了。
Java序列化反序列化原理及漏洞解决方案
Java序列化反序列化原理及漏洞解决⽅案Java序列化Java 提供了⼀种对象序列化的机制,该机制中,⼀个对象可以被表⽰为⼀个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。
Java反序列化反序列化就是将字节序列恢复为Java对象的过程整个过程都是 Java 虚拟机(JVM)独⽴的,也就是说,在⼀个平台上序列化的对象可以在另⼀个完全不同的平台上反序列化该对象,因此可以实现多平台之间的通信、对象持久化存储,主要有如下⼏个应⽤场景。
HTTP:多平台之间的通信,管理等RMI:是 Java 的⼀组拥护开发分布式应⽤程序的 API,实现了不同操作系统之间程序的⽅法调⽤。
值得注意的是,RMI 的传输 100% 基于反序列化,Java RMI 的默认端⼝是1099端⼝。
JMX:JMX 是⼀套标准的代理和服务,⽤户可以在任何 Java 应⽤程序中使⽤这些代理和服务实现管理,中间件软件 WebLogic 的管理页⾯就是基于 JMX 开发的,⽽ JBoss 则整个系统都基于 JMX 构架。
系列化反序列化基础序列化和反序列化本⾝并不存在问题。
但当输⼊的反序列化的数据可被⽤户控制,那么攻击者即可通过构造恶意输⼊,让反序列化产⽣⾮预期的对象,在此过程中执⾏构造的任意代码。
⼀个类的对象能够序列化的成功需要两个条件该类必须实现 java.io.Serializable 接⼝该类的所有属性必须是可序列化的。
如果有⼀个属性不是可序列化的,则该属性必须注明是短暂的。
漏洞基本原理简单的反序列化Demo⾸先定义对象类Persion,包含两个参数public class implements java.io.Serializable{public String name;public int age;public void info(){System.out.println("Name:"++";nAge:"+this.age);}}在主类中声明对象,并且将对象序列化为⼆进制⽂件,将其存储到硬盘中import java.io.*;public class Main{public static void main(String [] args){将对象序列化为⼆进制⽂件Persion p = new Persion(); = "Joner";p.age = 18;try {//打开⼀个⽂件输⼊流FileOutputStream fileOut = new FileOutputStream("D:\test\test.db");//建⽴对象输⼊流ObjectOutputStream out = new ObjectOutputStream(fileOut);//输出反序列化对象out.writeObject(p);out.close();fileOut.close();System.out.printf("保存成功");}catch(IOException i){i.printStackTrace();}}进⾏反序列化import java.io.*;public class Main{public static void main(String [] args){/*从⼆进制⽂件中提取对象*/Persion persion = null;try{FileInputStream fileInputStream = new FileInputStream("D:\test\test.db");//建⽴对象输⼊流ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);persion = (Persion) inputStream.readObject();inputStream.close();fileInputStream.close();}catch (ClassNotFoundException c){System.out.println("对象未找到");c.printStackTrace();return;} catch (FileNotFoundException e) {e.printStackTrace();return;} catch (IOException e) {e.printStackTrace();return;}System.out.println("反序列化对象.......");System.out.println("Name:"+);System.out.println("Age:"+persion.age);}}查看test.db⽂件的内容可以看见如下内容其中 AC ED 00 05 是java 序列化内容的特征,其中00 05 是版本信息,base64编码后为ro0AB反序列化漏洞Demo在上⾯的Demo中可以看到,进⾏反序列化时会调⽤readObject()⽅法,如果readObject⽅法书写不当就会引发漏洞。
JAVA反序列化漏洞解决办法
JAVA反序列化漏洞解决办法⼀、漏洞描述:近期,反序列化任意代码执⾏漏洞持续发酵,越来越多的系统被爆出存在此漏洞。
Apache Commons⼯具集⼴泛应⽤于JAVA技术平台,存在Apache Commons Components InvokerTransformer反序列化任意代码执⾏漏洞, WebLogic、IBM WebSphere、JBoss、Jenkins和OpenNMS等应⽤都⼤量调⽤了Commons⼯具集,通过远程代码执⾏可对上述应⽤发起远程攻击。
⼆、漏洞解决办法:1 使⽤ SerialKiller 替换进⾏序列化操作的 ObjectInputStream 类;2 在不影响业务的情况下,临时删除掉项⽬⾥的“org/apache/commons/collections/functors/InvokerTransformer.class” ⽂件;在服务器上找org/apache/commons/collections/functors/InvokerTransformer.class类的jar,⽬前weblogic10以后都在Oracle/Middleware/modules下mons.collections_3.2.0.jar,创建临时⽬录tt,解压之后删除InvokerTransformer.class类后再打成mons.collections_3.2.0.jar覆盖Oracle/Middleware/modules下,重启所有服务。
如下步骤是linux详细操作⽅法:A)mkdir ttB)cp -r Oracle/Middleware/modules/mons.collections_3.2.0.jar ./ttC)jar xf Oracle/Middleware/modules/mons.collections_3.2.0.jarD)cd org/apache/commons/collections/functorsE)rm -rf InvokerTransformer.classF)jar cf mons.collections_3.2.0.jar org/* META-INF/*G)mv mons.collections_3.2.0.jar Oracle/Middleware/modules/H)重启服务三、漏洞解决办法:1、假如不是处理weblogic⾃带的mons.collections_3.2.0.jar,⽽是修改应⽤代码collections_*.jar,⼀定在发版本不能覆盖。
Java反序列化漏洞研究
Java反序列化漏洞研究Java反序列化漏洞研究1. 漏洞原理java序列化就是把对象转换成字节流,便于保存在内存、⽂件、数据库中;反序列化即逆过程,由字节流还原成对象。
当反序列化的输⼊来源于程序外部,可以被⽤户控制,恶意⽤户便可以构造恶意的字节流,经反序列化之后得到精⼼构造的恶意对象。
也就是说⼀些java应⽤的数据在⽹络中传输,我们把⾥⾯的序列化数据抠出来,替换成我们的payload,应⽤程序接收之后把payload 进⾏反序列化,构造的恶意功能(如命令执⾏)就被执⾏了。
实际过程中直接忽略PCA的存在,hacker先于PCB完成⼀些前期的交互。
那么问题来了,如何构造能执⾏任意命令的payload?需要依赖于什么条件?哪些应⽤会在⽹络中传输序列化的数据?这些数据有什么特征?1. 序列化与反序列化原理上述代码说明了反序列化的过程,Java中通过writeObject()函数对对象进⾏序列化,将有结构的数据转换成为⽆结构的⼆进制串。
通过readObject()函数将⼆进制串反序列化还原成对象。
执⾏到12⾏时⽣成了⼀个String类型的对象。
执⾏到16⾏已经将序列化数据写⼊到object.db中了,前⾯的四个字节AC ED 00 05开头,后⾯会经常⽤到。
执⾏到24⾏,完成反序列化过程,将对象还原,此时对象id不同,其他均相同。
1. 构造执⾏任意命令的payload下⾯的代码能快速的体验payload是如何构造的。
程序1的RunInvo类,构造了⼀个MAP,再⽤它构造AnnotationInvocationHandler对象,将这个对象序列化到payload.bin中。
程序2读取payload.bin中的数据,通过readObject()进⾏反序列化,代码得到执⾏,弹出计算器,如下图所⽰。
代码执⾏关键点:AnnotationInvocationHandler,TransformedMap.decorate,InvokerTransformer从序列化数据传⼊readObject()开始解释为什么要依赖于这⼏个关键点。
Java安全之Fastjson反序列化漏洞分析
Java安全之Fastjson反序列化漏洞分析Java安全之Fastjson反序列化漏洞分析⾸发:先知论坛0x00 前⾔在前⾯的RMI和JNDI注⼊学习⾥⾯为本次的Fastjson打了⼀个⽐较好的基础。
利于后⾯的漏洞分析。
0x01 Fastjson使⽤在分析漏洞前,还需要学习⼀些Fastjson库的简单使⽤。
Fastjson概述FastJson是啊⾥巴巴的的开源库,⽤于对JSON格式的数据进⾏解析和打包。
其实简单的来说就是处理json格式的数据的。
例如将json转换成⼀个类。
或者是将⼀个类转换成⼀段json数据。
在我前⾯的学习系列⽂章中其实有⽤到jackson。
其作⽤和Fastjson差不多,都是处理json数据。
可参考该篇⽂章:。
其实在jackson⾥⾯也是存在反序列化漏洞的,这个后⾯去分析,这⾥不做赘述。
Fastjson使⽤使⽤⽅式://序列化String text = JSON.toJSONString(obj);//反序列化VO vo = JSON.parse(); //解析为JSONObject类型或者JSONArray类型VO vo = JSON.parseObject("{...}"); //JSON⽂本解析成JSONObject类型VO vo = JSON.parseObject("{...}", VO.class); //JSON⽂本解析成VO.class类Fastjson序列化代码实例:定义⼀个实体类package com.fastjson.demo;public class User {private String name;private int age;public User() {}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}public String getName() {return name;}public void setName(String name) { = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public User(String name, int age) { = name;this.age = age;}}定义⼀个test类:package com.fastjson.demo;import com.alibaba.fastjson.JSON;public class test {public static void main(String[] args) {User user = new User();user.setAge(18);user.setName("xiaoming");String s = JSON.toJSONString(user);System.out.println(s);}}运⾏后结果为:{"age":18,"name":"xiaoming"}这是⼀段标准模式下的序列化成JSON的代码,下⾯来看另⼀段。
Java反序列化漏洞学习
Java反序列化漏洞学习序列化是Java提供的⼀种对象持久化保存的技术。
常规对象在程序结束后会被回收,如果想把对象持久保存⽅便下次使⽤,需要序列化和反序列化。
序列化有两个前提:类必须实现.serializable接⼝类所有字段都必须是可序列化的反序列化漏洞利⽤原理1. 利⽤重写ObjectInputStream的readObject重写ObjectInputStream的readObject⽅法时,可执⾏恶意代码。
定义⼀个类,并实现serializable接⼝:public class User implements Serializable {public String name;public int age;public String getUserInfo(){return "user name: "+ +" age: "+this.age;}}View Code对这个类进⾏序列化和反序列化(将序列化对象保存在user.txt中):public class SerializeDemo {public static void main(String[] args) throws IOException, ClassNotFoundException {User user = new User(); = "路⼈";user.age = 25;try {FileOutputStream fileOut = new FileOutputStream("user.txt");ObjectOutputStream out = new ObjectOutputStream(fileOut);out.writeObject(user);out.close();fileOut.close();System.out.println("Serialized done");} catch (IOException e) {e.printStackTrace();}User user_out = null;FileInputStream fileInput = new FileInputStream("user.txt");ObjectInputStream in = new ObjectInputStream(fileInput);user_out = (User) in.readObject();in.close();fileInput.close();System.out.println(user_out.getUserInfo());}}View Code执⾏结果:user类重写readObject⽅法,并将恶意代码写在重写⽅法中:private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject();Runtime.getRuntime().exec("touch hello.txt");}View Code执⾏序列化和反序列化之后,恶意代码执⾏成功:2. 利⽤反射反射可以越过静态检查和类型约束,在运⾏期间访问和修改对象的属性和状态。
15.Java反序列化漏洞说明
JBoss、Jenkins、OpenNMS 这些应用的反序列化漏洞能够得以利用
,就是依靠了 Apache Commons Collections这种公用库。
国家信息安全漏洞共享平台(CNVD)收录了Apache Commons Components InvokerTransformer反序列化任意代码执行漏洞( CNVD-2015-07556),该漏洞影响多款应用广泛的Web容器软件。远 程攻击者利用漏洞可在目标系统上执行任意代码,危害较大的可以取 得网站服务器控制权。
代码执行。
博客中提到,早在2015年的1月28 号,Gabriel Lawrence (@gebl)和Chris Frohoff (@frohoff)在AppSecCali上给出了一个报告,报告中介绍了Java反序列化漏洞可
以利用Apache Commons Collections 这个常用的Java 库来实现任意代码执行,
原理
如果Java 应用对用户输入,即不可信数据做了反序列化处理,并且没 有对用户可控的序列化代码进行校验而是直接进行反序列化使用,
那么攻击者可以通过构造恶意输入,让反序列化产生非预期的对象,
非预期的对象在产生过程中就有可能带来任意代码执行,触发一些 意想不到的漏洞。
所以这个问题的根源在于类 ObjectInputStream在反序列化时,没有 对生成的对象的类型做限制;假若反序列化可以设置 Java 类型的白
Java反序列化漏洞说明
Java反序列化漏洞说明
内容安排
背景说明 漏洞简介 原理 影响范围 修复建议 验证测试
背景说明
2015 年11月6日,FoxGlove Security 安全团队的@breenmachine 发布的一篇博
jackson 反序列化 枚举的问题
jackson 反序列化枚举的问题在Jackson中反序列化枚举类型时,可能会遇到一些问题。
下面是一些可能的问题和解决方法:1. 反序列化枚举失败:这可能是因为Jackson无法识别输入的字符串与枚举类型之间的映射关系。
可以使用注解`@JsonCreator`和`@JsonValue`来指定自定义的映射规则。
```javapublic enum MyEnum {VALUE1("value1"),VALUE2("value2");private String value;MyEnum(String value) {this.value = value;}@JsonCreatorpublic static MyEnum fromValue(String value) {for (MyEnum e : MyEnum.values()) {if (e.value.equals(value)) {return e;}}throw new IllegalArgumentException("Invalid value: " + value);}@JsonValuepublic String toValue() {return value;}}```2. 反序列化空字符串失败:如果输入的字符串是空字符串,Jackson默认情况下会抛出异常。
可以使用`@JsonSetter`注解指定为空字符串时的默认值。
```javapublic enum MyEnum {VALUE1,VALUE2;@JsonSetterpublic void setValue(String value) {if (value != null && !value.isEmpty()) {throw new IllegalArgumentException("Invalid value: " + value);}}}```3. 反序列化大小写不敏感的枚举:默认情况下,Jackson会按照枚举定义的顺序进行匹配,这意味着枚举类型的字符串必须完全匹配大小写。
Java反序列化漏洞实现
Java反序列化漏洞实现⼀、说明以前去⾯试被问反序列化的原理只是笼统地答在参数中注⼊⼀些代码当其反序列化时被执⾏,其实“⼀些代码”是什么代码“反序列化”时为什么就会被执⾏并不懂;反来在运营商做⼄⽅经常会因为java反反序列化漏洞要升级commons.collections或给中间件打补丁,前⾯说的两个问题还是不懂;今天⼜研究了番,也还不是很懂只是能弹计算器暂且先记⼀下。
⼆、序列化和反序列化序列化和反序列化应该是在学《java⽹络编程》的时候就写过了,所谓序列化就是把对象从内存写到磁盘⽂件或数据库,反序列化就是从磁盘⽂件或数据库读取对象。
注意序列化和反序列化都是针对对象不是类也不⽅法。
⼀直不明⽩为件么保存到⽂件要另外起个名字“序列化”,所以在相当长⼀段时间内都不敢肯定序列化就是写⽂件。
以下直接举例明确序列化与反序列化的概念。
2.1 序列化对象对应类我们这⾥使⽤的类很简单,就只设置了⼀个叫name的属性;另外凡需要序列化的类都需要实现Serializable接⼝package com.ls.serdemo;import java.io.Serializable;class SerObj implements Serializable {public String name;}2.2 序列化序列化,我们这⾥就是实例化2.1中的SerObj类设置⼀下其name属性,然后保存到object.ser⽂件package com.ls.serdemo;import java.io.*;public class SerImp {public static void main(String args[]) throws Exception{// 实例化对象SerObj serObj = new SerObj(); = "serobj";// 以下就是序列化操作// 打开object.ser⽂件FileOutputStream fos = new FileOutputStream("object.ser");ObjectOutputStream oos = new ObjectOutputStream(fos);// 使⽤writeObject()⽅法将serObj对象写到object.ser⽂件oos.writeObject(serObj);oos.close();fos.close();}}完成后object.ser内容如下:2.3 反序列化package com.ls.serdemo;import java.io.*;public class DeSerImp {public static void main(String args[]) throws Exception{// 以下就是反序列化操作// 打开object.ser⽂件FileInputStream fis = new FileInputStream("object.ser");ObjectInputStream ois = new ObjectInputStream(fis);// 使⽤从object.ser⽂件中读取对象SerObj deSerObj = (SerObj) ois.readObject();System.out.println();ois.close();fis.close();}}运⾏可以看到成功打印name属性三、反序列化漏洞反序列化漏洞不是java独有的其他语⾔也会有,但都⼀样是在反序列化时执⾏了注⼊的代码。
java~jackson实现接口的反序列化
java~jackson实现接⼝的反序列化jackson是springboot中集成的序列化⽅式,是默认的json序列化⽅式,当然你可以使⽤其它的序列化⼯具代替它,不过今天我们还是说⼀下它,使⽤jackson进⾏序列化⼀个类,然后再把它的JSON字符反序列化为它的接⼝对象。
现实这种⽅式默认是不⾏的,因为接⼝不能被⾃动实例化使⽤redisTelmplete时,如果使⽤objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);这种试序列化,由于会把实例类型写到时JSON⾥,所以也不能反序列化为接⼝⼏个序列化⽅式⼀序列化为具体类型,⽆法反序列化接⼝,即你⽤什么类型序列化的,就⽤什么类型反序列化,它经常与redis的序列化Jackson2JsonRedisSerializer⼀起使⽤。
ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);User user = new User();user.setUsername("lind");user.setEmail("zzl@");String msg = om.writeValueAsString(user);结果["mon.JacksonTest$User",{"username":"lind","email":"zzl@","authorities":null}]⼆序列化为字符串,主要好处是与类型⽆关,只要字段可以配置上,就可以反序列化,并且在⾃定义序列化器定义之后,还可以对接⼝类型进⾏反序列化,可以说更加⽅便。
java反序列化漏洞实战
java反序列化漏洞实战
准备:
1. 域名⼀个,⽤于增加NS解析,判断是否存在反序列化漏洞。
2. 公⽹IP服务器⼀台,⽤于搭建DNS代理,抓包判断。
3. dnschef,DNS代理
4. ysoserial.jar⽣成payload.
5. 简单的python脚本,调⽤ysoserial.jar并发送payload
⾸先域名增加⼀条A记录解析到公⽹IP服务,然后增加⼀条NS记录指向这条A记录。
然后公⽹IP服务器开防⽕墙端⼝53,记得是UDP协议。
然后运⾏dnschef,记得安装dnslib,否则⽆法正常运⾏。
然后运⾏记得带参数,不要⽤默认参数。
否则只会监听127.0.0.1。
例:
dnschef.py --interface 0.0.0.0 –q
调⽤ysoserial中的URLDNS,如果存在反序列化漏洞,服务器应该会有解析域名的⽇志。
接下来就是测试存在哪个反序列化漏洞了。
测试漏洞需要先在服务器上开启tcpdump icmp 抓ping包,再然后使⽤python脚本调⽤ysoserial发送ping 服务器IP的命令,ping 1次就可以了,所以记得指定n或者c。
然后如果看到服务器有抓到ping的包,证明此漏洞可以利⽤。
分析jackjson的安全漏洞CVE-2019-14379
分析jackjson的安全漏洞CVE-2019-14379Jackson 是当前⽤的⽐较⼴泛的,⽤来序列化和反序列化 json 的 Java 的开源框架。
Jackson 社区相对⽐较活跃,更新速度也⽐较快,从 Github 中的统计来看,Jackson 是最流⾏的 json 解析器之⼀。
今天给⼤家介绍jackson知识点序列化和反序列化的时候,setName和getName调⽤顺序: Student.java:package com.test.JackSonTest;public class Student{private String name;private Integer age;private Teacher teacher;public Student(){System.out.println("student构造⽅法被调⽤");};public String getName() {System.out.println(11111);return name;}public void setName(String name) {System.out.println(2222); = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public Teacher getTeacher() {return teacher;}public void setTeacher(Teacher teacher) {this.teacher = teacher;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", teacher=" + teacher +'}';}} 在setName和getName处,新增输出语句: 调⽤测试类: jackson序列化和反序列化:@Testpublic void test2() throws IOException {//序列化对象转json字符串Student student = new Student();student.setName("jack");student.setAge(20);student.setTeacher(new Teacher("lua",33));ObjectMapper objectMapper = new ObjectMapper();//序列化JSON串时,在值上打印出对象类型objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);String result = objectMapper.writeValueAsString(student);System.out.println(result);//反序列化 json字符串转对象String jsonResult = "[\"com.test.JackSonTest.Student\",{\"name\":\"jack\",\"age\":20,\"teacher\":[\"com.test.JackSonTest.Teacher\",{\"name\":\"lua\",\"age\":33}]}]";Student stu = objectMapper.readValue(jsonResult, Student.class);System.out.println(stu);} 输出结果: student构造⽅法被调⽤222211111["com.test.JackSonTest.Student",{"name":"jack","age":20,"teacher":["com.test.JackSonTest.Teacher",{"name":"lua","age":33}]}]student构造⽅法被调⽤2222teacher构造⽅法被调⽤Student{name='jack', age=20, teacher=Teacher{name='lua', age=33}} 结论:在序列化的时候调⽤set*,然后调⽤get*⽅法,反序列化的时候会调⽤set*⽅法,不会调⽤get*⽅法,调⽤反序列化的json数据对应的类构造⽅法 CVE-2019-14379漏洞分析: 影响jackson到2.9.9.1: 这个漏洞还是⽐较有意思的,其他的cve,我都看了下,都⽐较简单: 先安装漏洞环境依赖: pom.xml:<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.8</version></dependency><dependency><groupId>net.sf.ehcache</groupId><artifactId>ehcache</artifactId><version>2.10.6</version></dependency><dependency><groupId>javax</groupId><artifactId>javaee-api</artifactId><version>6.0</version></dependency> 单单有ehcache依赖是不⾏的,还得有javaee包,否则调⽤ehcache的时候,会提⽰找不到! 反序列化的恶意类是:net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup 因为代码量的原因,直接静态调试了,不是很难,通过反射进⼊代码: 进⼊类: 找到这段代码:public void setProperties(Properties properties) {if (properties != null) {String jndiName = properties.getProperty("jndiName");if (jndiName != null) {this.defaultJndiSelector.setJndiName(jndiName);}}} 获取jndiName的值,然后设置jndiName: 继续看这个类的其他⽅法:public DefaultTransactionManagerLookup() {this.transactionManagerSelectors = new Selector[]{this.defaultJndiSelector, new GlassfishSelector(), new WeblogicSelector(), new BitronixSelector(), new AtomikosSelector()}; } 定义数组,存储了这些数据,其中包含了this.defaultJndiSelector,这是重点,等下会⽤到 this.defaultJndiSelector的来源:private final JndiSelector defaultJndiSelector = new GenericJndiSelector(); 发现defaultJndiSelector实例化了GenericJndiSelector 这个等下要⽤到,这个先标记下. 继续看这个类的其他⽅法:getTransactionManager(): 代码如下:public TransactionManager getTransactionManager() {if (this.selector == null) {this.lock.lock();try {if (this.selector == null) {this.lookupTransactionManager();}} finally {this.lock.unlock();}}return this.selector.getTransactionManager();} 跟进去this.lookupTransactionManager(): 其中Selector[] var1 = this.transactionManagerSelectors;int var2 = var1.length; 获取的数组内容,就是DefaultTransactionManagerLookup类提供的,继续往下⾛代码: 跟进去:public TransactionManager getTransactionManager() {if (this.transactionManager == null) {this.transactionManager = this.doLookup();}return this.transactionManager;} 调⽤this.doLookup()⽅法: 跟进去: 跟进到了Selector类,发现这是个抽象类: 以前写⽂章说过,java基础:抽象类⽅法的实现在他的⼦类继承,如果想实现抽象类中的⽅法,需要⼦类继承⽗类,然后重写⽅法. 寻找他的⼦类: 跟进去看看: 快速找doLookup的具体实现: 把代码搞出来:protected TransactionManager doLookup() {InitialContext initialContext;try {initialContext = new InitialContext();} catch (NamingException var14) {LOG.debug("cannot create initial context", var14);return null;}try {TransactionManager var3;try {Object jndiObject = initialContext.lookup(this.getJndiName());if (jndiObject instanceof TransactionManager) {var3 = (TransactionManager)jndiObject;return var3;} 发现调⽤lookup,远程调⽤我们的jndiName,jndiName可以通过properties设置:Object jndiObject = initialContext.lookup(this.getJndiName()); ⾄此都分析完了,触发jndi远程调⽤的⽂件是:net/sf/ehcache/ehcache/2.10.6/ehcache-2.10.6.jar!/net/sf/ehcache/transaction/manager/selector/JndiSelector.class 只要我们设置我们的jndiName为恶意地址,并且调⽤getTransactionManager⽅法,即可实现rce: 构造exp:package com.test.JackSonTest;import com.fasterxml.jackson.databind.ObjectMapper;import com.mysql.jdbc.MiniAdmin;import net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup;import org.jdom.transform.XSLTransformException;import org.jdom.transform.XSLTransformer;import java.io.IOException;import java.sql.SQLException;import java.util.Properties;public class attackJdbc {public static void main(String[] args) throws ClassNotFoundException, IOException, SQLException, XSLTransformException {ObjectMapper objectMapper =new ObjectMapper();Class.forName("org.jdom.transform.XSLTransformer");Class.forName("net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup");objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);String json2 = "[\"net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup\",{\"properties\":[\"java.util.Properties\",{\"jndiName\":\"ldap://119.45.227.86:123\"}]}]";Object o = objectMapper.readValue(json2, Object.class);objectMapper.writeValueAsString(o);}} 这⾥要writeValueAsString序列化⼀次,是因为只有调⽤get⽅法的时候才能触发lookup远程调⽤,所以这⾥需要序列化⼀次 运⾏代码: 关于恶意json的构造,参考⼀开始写的测试类中序列化的⽣成,我是根据序列化⽣成json反推出来的恶意json 浅蓝提供的exp是:String poc = "[\"net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup\",{\"properties\":{\"jndiName\":\"ldap://119.45.227.86:123/hello\"}}]"; 这边执⾏提⽰我json格式错误... 真的学到了不少哈哈哈,还是⽐较有意思的,虽然实战很鸡肋.. 漏洞分析参考⽂章:以上就是jackjson的使⽤及CVE-2019-14379漏洞分析的详细内容,更多关于jackjson CVE-2019-14379漏洞的资料请关注其它相关⽂章!。
java 反序列化漏洞原理
java 反序列化漏洞原理Java反序列化漏洞原理在Java编程中,对象的序列化和反序列化是常见的操作。
通过序列化,可以将对象转化为字节流,方便存储和传输。
而通过反序列化,可以将字节流重新转化为对象。
然而,在反序列化的过程中存在着安全风险,即Java反序列化漏洞。
Java反序列化漏洞的原理可以简单概括为:攻击者利用恶意构造的序列化数据来触发目标系统的反序列化操作,从而实现攻击目标。
具体来说,Java反序列化漏洞的原理涉及到以下几个要点:1. 序列化和反序列化机制:Java提供了Serializable接口,通过实现该接口可以实现对象的序列化和反序列化。
在反序列化过程中,Java会根据序列化数据中的类名来查找并加载相应的类。
2. 类的加载:在反序列化过程中,Java会根据序列化数据中的类名来加载相应的类。
攻击者可以构造恶意的序列化数据,其中包含一个特殊的类名,这个类名指向了一个恶意的类。
3. 恶意类的利用:恶意类中可能存在一些危险的方法或代码,攻击者可以通过构造恶意的序列化数据,使得在反序列化过程中调用这些方法或执行这些代码。
这样一来,攻击者就能够在目标系统上执行任意代码,造成严重的安全威胁。
Java反序列化漏洞的危害非常严重,攻击者可以通过该漏洞执行任意代码,进而获取系统权限、篡改数据、拒绝服务等。
由于反序列化漏洞的原理是利用Java的反序列化机制,因此几乎所有使用Java反序列化功能的应用都有可能受到这种漏洞的影响。
为了防范Java反序列化漏洞,可以采取以下几种措施:1. 对反序列化进行严格限制:可以通过安全管理器来限制反序列化操作的权限,例如禁止反序列化恶意类所在的包或限制反序列化的深度。
2. 对输入进行有效过滤和验证:在反序列化操作前,应该对输入的序列化数据进行有效的过滤和验证,确保数据的合法性和完整性。
3. 使用安全的序列化方式:可以使用更加安全的序列化方式,例如JSON或XML,而不是Java默认的序列化方式。
Jackson--反序列化的解析
Jackson--反序列化的解析项⽬中经常需要调⽤指定服务的接⼝,并且对返回的json结果数据,进⾏反序列化⽣成java类。
若是返回的数据格式固定,那么直接按照固定的格式进⾏反序列化⽣成java类便可。
但是由于返回的结果数据格式不固定,需要⾃⼰编写反序列化类进⾏分析。
下⾯我讲展⽰下项⽬中遇到的情况。
{"status": "200","Goal": {"userId": "17090016","templateId": "26","templateName": "测试-营销通⽤⽬标模板","performance": [{"id": "8022","indexCode": "","name": "执⾏绩效综合达成率","category": "New Category","categoryName": "执⾏绩效","start": "2019-10-01T00:00:00.000","due": "2019-10-31T00:00:00.000","bizxTarget": "","bizxActual": "","done": "0.0","higedone": "","stateLabel": "重⼤延迟","weight": "","dataSource": "","lastModified": "2019-12-11T08:45:47.000","modifier": "17090016","children": ""},{"id": "8015","indexCode": "","name": "协访达成率","category": "Goals","categoryName": "先决条件","start": "2019-10-01T00:00:00.000","due": "2019-10-31T00:00:00.000","bizxTarget": "47.0","done": "0.0","higedone": "100.0","stateLabel": "重⼤延迟","weight": "","dataSource": "⼿持","lastModified": "2019-12-11T13:57:09.000","modifier": "17090016","children":{"childDescription": "CS协访","childTarget": "15","childActual": "18","childDone": "100.0"}},{"id": "8017","indexCode": "","name": "分销达成率","category": "New Category","categoryName": "执⾏绩效","start": "2019-10-01T00:00:00.000","due": "2019-10-31T00:00:00.000","bizxTarget": "100.0","bizxActual": "23.39","done": "23.39","higedone": "100.0","stateLabel": "重⼤延迟","weight": "20.0","dataSource": "订单管理","lastModified": "2019-12-11T14:09:32.000","modifier": "17090016","children": [{"childDescription": "门店数","childTarget": "","childActual": "23","childDone": ""},{"childDescription": "门店品类数","childActual": "31","childDone": ""},{"childDescription": "门店SKU","childTarget": "","childActual": "25","childDone": ""}]}}上⾯的json格式数据中,其余的字段格式都是⽐较的固定,但是可以看到children的数据内容出现了3种:1、字符串内容2、对象3、数组由于children的内容格式不固定,则直接利⽤jackson进⾏反序列化会失败,所以需要我们⾃⼰编写反序列化的实现类。
序列化漏洞检查思路
序列化漏洞检查思路下载温馨提示:该文档是我店铺精心编制而成,希望大家下载以后,能够帮助大家解决实际的问题。
文档下载后可定制随意修改,请根据实际需要进行相应的调整和使用,谢谢!并且,本店铺为大家提供各种各样类型的实用资料,如教育随笔、日记赏析、句子摘抄、古诗大全、经典美文、话题作文、工作总结、词语解析、文案摘录、其他资料等等,如想了解不同资料格式和写法,敬请关注!Download tips: This document is carefully compiled by the editor. I hope that after you download them, they can help yousolve practical problems. The document can be customized and modified after downloading, please adjust and use it according to actual needs, thank you!In addition, our shop provides you with various types of practical materials, such as educational essays, diary appreciation, sentence excerpts, ancient poems, classic articles, topic composition, work summary, word parsing, copy excerpts,other materials and so on, want to know different data formats and writing methods, please pay attention!序列化漏洞是软件安全领域中一种重要的安全威胁,它可以被恶意攻击者利用来执行未授权操作、绕过访问控制、远程代码执行等危险行为。
Java反序列化漏洞总结
Java反序列化漏洞总结前⾔什么是序列化和反序列化Java 提供了⼀种对象序列化的机制,该机制中,⼀个对象可以被表⽰为⼀个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。
反序列化就是通过序列化后的字段还原成这个对象本⾝。
但标识不被序列化的字段是不会被还原的。
序列化有什么⽤1)⽹站相应的session对象存储在硬盘上,那么保存在session中的内容就必须实现相关的序列化操作。
2)如果使⽤的java对象要在分布式中使⽤或者在rmi远程调⽤的⽹络中使⽤的话,那么相关的对象必须实现java序列化接⼝。
Java反序列化类型我们最常见就是原⽣的java反序列化类型,其实java中有⼏种⽅式可以执⾏反序列化,本⽂⽬的也是对这⼏种类型的反序列化⽅法进⾏归纳和总结。
1、 Java原⽣序列化Java包中⾃带的类InputStream和OutputStream,它们之间可以互相转化,使⽤writeObject序列化,使⽤readObject反序列化。
import java.io.*;public class DeserializeDemo{public static void main(String [] args){Employee e = null;try{FileInputStream fileIn = new FileInputStream("/tmp/employee.ser");ObjectInputStream in = new ObjectInputStream(fileIn);e = (Employee) in.readObject();in.close();fileIn.close();}catch(IOException i){i.printStackTrace();return;}catch(ClassNotFoundException c){System.out.println("Employee class not found");c.printStackTrace();return;}System.out.println("Deserialized Employee...");System.out.println("Name: " + );System.out.println("Address: " + e.address);System.out.println("SSN: " + e.SSN);System.out.println("Number: " + e.number);}}2、 Json反序列化Json序列化⼀般会使⽤jackson包,通过ObjectMapper类来进⾏⼀些操作,⽐如将对象转化为byte数组或者将json串转化为对象。
Java反序列化之Jackson-databind(CVE-2017-17485)
Java反序列化之Jackson-databind(CVE-2017-17485)这个洞的cve编号:CVE-2017-17485,漏洞环境就如第⼀个链接那样,jdk需要在jdk 1.8以上。
先看⼀下Jackson-databind的⽤法,说⽩了就是将json转换成对象。
test-legit.json代码如下{"id":123}运⾏结果如图:如果注⼊的json代码如下代码,就会引⼊FileSystemXmlApplicationContext这个类,去下载spel.xml:{"id":123, "obj": ["org.springframework.context.support.FileSystemXmlApplicationContext", "https:///irsl/jackson-rce-via-spel/master/sp spel.xml配置如下:<beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans.xsd"><bean id="pb" class="ng.ProcessBuilder"><constructor-arg value="calc.exe" /><property name="whatever" value="#{ pb.start() }"/></bean></beans>下断点调试⼀下,F7跟进readValue函数。
JAVA反序列化漏洞入门学习笔记(一)--反序列化简介
JAVA反序列化漏洞⼊门学习笔记(⼀)--反序列化简介JAVA 真的令⼈头⼤参考⽂章JAVA 序列化与反序列化简介同 PHP/Python 类似,java 序列化的⽬的是将程序中对象状态转换成以数据流形式,反序列化是将数据流恢复为对象。
此举可以有效地实现多平台之间的通信、对象持久化存储。
序列化实例import java.io.*;//定义⼀个可序列化的类,该类必须实现 java.io.Serializable 接⼝class Giao implements java.io.Serializable{public String name;public String motto;public void saygiao(){System.out.println(this.motto);}// ⾃定义 readObject ⽅法private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{//执⾏默认的readObject()⽅法in.defaultReadObject();//执⾏命令Runtime.getRuntime().exec("calc.exe");}}//序列化/反序列化public class SerializeGiao{public static void main(String [] args) throws IOException, ClassNotFoundException{//实例化⼀个可序列化对象Giao testClass = new Giao(); = "说唱带师";testClass.motto = "⼀给我哩 giao giao!";//序列化//将序列化后的对象写⼊到⽂件FileOutputStream fos = new FileOutputStream("test.ser");ObjectOutputStream os = new ObjectOutputStream(fos);os.writeObject(testClass);os.close();fos.close();//反序列化Giao obj = null;//从⽂件读取序列化的结果后进⾏反序列化FileInputStream fis = new FileInputStream("test.ser");ObjectInputStream ois = new ObjectInputStream(fis);obj = (Giao)ois.readObject();ois.close();fis.close();System.out.println();System.out.println(obj.motto);}}//由此可见:⼈⽣苦短,我⽤ Python序列化结果:反序列化结果:序列化条件⼀个类的对象要想序列化成功,必须满⾜两个条件:该类必须实现 java.io.Serializable 或 java.io.Externalizable 接⼝。
jackson中自定义处理序列化和反序列化
jackson中⾃定义处理序列化和反序列化/blog/2005323**********************************************对于⼀直⽤gson的⼈来说,如果单独⽤jackson,真是⿇烦了,但还是得⼩结下了:先来看下如何⾃定义把某个对象序列化为json:先是对象:Java代码public class User {public int id;public String name;}public class Item {public int id;public String itemName;public User owner;}JACKSON⼀般的使⽤很容易,如;Item myItem = new Item(1, "theItem", new User(2, "theUser"));String serialized = new ObjectMapper().writeValueAsString(myItem);结果为:{"id": 1,"itemName": "theItem","owner": {"id": 2,"name": "theUser"}}如果要输出为如下的样⼦,⽐如;{"id": 25,"itemName": "FEDUfRgS","owner": 15}则要⾃定义了,要继承JsonSerializer类,如下:public class ItemSerializer extends JsonSerializer<Item> {@Overridepublic void serialize(Item value, JsonGenerator jgen, SerializerProvider provider)throws IOException, JsonProcessingException {jgen.writeStartObject();jgen.writeNumberField("id", value.id);jgen.writeStringField("itemName", value.itemName);jgen.writeNumberField("owner", value.owner.id);jgen.writeEndObject();}}然后Item myItem = new Item(1, "theItem", new User(2, "theUser"));ObjectMapper mapper = new ObjectMapper();SimpleModule module = new SimpleModule();module.addSerializer(Item.class, new ItemSerializer());mapper.registerModule(module);String serialized = mapper.writeValueAsString(myItem);看,相当复杂,然后看有⽆办法简单点,其实是有的哦;⽅法为:@JsonSerialize(using = ItemSerializer.class)public class Item {...}就是使⽤注解@JsonSerialize,然后:Item myItem = new Item(1, "theItem", new User(2, "theUser"));String serialized = new ObjectMapper().writeValueAsString(myItem);接下来看如何反序列化了,同样,要反序列化的两个pojo为:public class User {public int id;public String name;}public class Item {public int id;public String itemName;public User owner;}反序列化代码为:Item itemWithOwner = new ObjectMapper().readValue(json, Item.class);如果要⾃定义反序列化,⽐如要反序列化的JSON为;{"id": 1,"itemName": "theItem","owner": 2}则上⾯这样会报错:com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "createdBy" (class org.baeldung.jackson.dtos.Item), not marked as ignorable (3 known properties: "id", "owner", "itemName"]) at [Source: java.io.StringReader@53c7a917; line: 1, column: 43] (through reference chain: org.baeldung.jackson.dtos.Item["createdBy"])代码:public class ItemDeserializer extends JsonDeserializer<Item> {@Overridepublic Item deserialize(JsonParser jp, DeserializationContext ctxt)throws IOException, JsonProcessingException {JsonNode node = jp.getCodec().readTree(jp);int id = (Integer) ((IntNode) node.get("id")).numberValue();String itemName = node.get("itemName").asText();int userId = (Integer) ((IntNode) node.get("id")).numberValue();return new Item(id, itemName, new User(userId, null));}}ObjectMapper mapper = new ObjectMapper();SimpleModule module = new SimpleModule();module.addDeserializer(Item.class, new ItemDeserializer());mapper.registerModule(module);Item readValue = mapper.readValue(json, Item.class);也可以⽤注解:@JsonDeserialize(using = ItemDeserializer.class)public class Item {...}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
源码分析Jackson反序列化漏洞前言:本次分析从Java序列化和反序列化源码开始分析,进一步分析Jackson源码,找出造成漏洞的原因,最后以Jackson2.9.2版本,JDK1.80_171,resin4.0.52,CVE-2020-10673为例复现漏洞。
一.JA V A反序列化原理1.1 Class对象每一个类都有一个Class对象,Class对象包含每一个类的运行时信息,每一个类都有一个Class对象,每编译一个类就产生一个Class对象,Class类没有公共的构造方法,Class对象是在类加载的时候由JVM以及通过调用类加载器中的DefineClass()方法自动构造的,因此不能显式地声明一个Class对象。
在类加载阶段,类加载器首先检查这个类的Class对象是否已经被加载。
如果尚未加载,默认的类加载器就会根据类的全限定名查找.class文件。
一旦某个类的Class对象被载入内存,我们就可以它来创建这个类的所有对象以及获得这个类的运行时信息。
获得Class对象的方法:1).Class.forName(“类的全名”);//com.xx.xx.xx2).实例对象.getClass()3).类名.class1.2反射JA V A反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
实现Java反射机制的类都位于ng.reflect包中:1).Class类:代表一个类2).Field类:代表类的成员变量(类的属性)3).Method类:代表类的方法4).Constructor类:代表类的构造方法5).Array类:提供了动态创建数组,以及访问数组的元素的静态方法简单反射调用代码Class clz=this.getClass();Object obj= clz.getMethod("方法名",Class对象序列).invoke(this,Object参数序列);1.3 反序列化Java 序列化是指把Java 对象转换为字节序列的过程便于保存在内存、文件、数据库中,ObjectOutputStream类的writeObject() 方法可以实现序列化。
Java 反序列化是指把字节序列恢复为Java 对象的过程,ObjectInputStream 类的readObject() 方法用于反序列化。
RMI:是Java 的一组拥护开发分布式应用程序的API,实现了不同操作系统之间程序的方法调用。
值得注意的是,RMI 的传输100% 基于反序列化,Java RMI 的默认端口是1099 端口。
JMX:JMX 是一套标准的代理和服务,用户可以在任何Java 应用程序中使用这些代理和服务实现管理,中间件软件WebLogic 的管理页面就是基于JMX 开发的,而JBoss 则整个系统都基于JMX 构架。
只有实现了Serializable接口的类的对象才可以被序列化,Serializable 接口是启用其序列化功能的接口,实现java.io.Serializable 接口的类才是可序列化的,没有实现此接口的类将不能使它们的任一状态被序列化或逆序列化。
readObject() 方法的作用正是从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回,readObject() 是可以重写的,可以定制反序列化的一些行为。
readObject()主要做的事情,其实就是读取正常应该被序列化的字段信息后,再构造出一个map,再通过对象流,将原有通过对象流写进文件里面的map信息(容量,每个item信息等)全部读取出来,然后重新构造一个map,这样就使得我们保存在set里面的信息,在经历过对象流的序列化和反序列化后,都没有丢失。
1.4 readObject()分析1).进入readObject()源码,首先判断是否调用readObjectOverride(),其中enableOverride的值由ObjectInputStream类的构造函数决定,带参构造为false,无参构造为true。
但readObjectOverride()函数为空方法。
因此一般需要带参构造。
2).调用readObject0(),进入函数中,发现有一大部分的switch判断,该部分判断读入的流是什么类型。
其中readOrdinaryObject()值得注意,因为读入的大部分都是要反序列化的对象数据流。
1.5 readOrdinaryObject()函数中readClassDesc()分析1.进入readOrdinaryObject()函数,发现一开始,调用readClassDesc(),进而调用checkDeserialize()。
如下图:2.readClassDesc()函数中,switch判断顶端字节特征,选择执行的函数3.无参构造创建ObjectStreamClass()对象,调用initNonProxy().4.过程中调用了lookup(Class,boolean)方法5.进入lookup方法,生成一个带参构造的ObjectStreamClass对象,这个对象就是下面要提到的readOrdinaryObject()函数中的readSerialData()的第一个参数。
1.6 readOrdinaryObject()函数中readSerialData()分析1.进入readSerialData(),注意obj参数2.进入invokeReadObject(),发现obj参数(该参数上文提到)直接经过反射调用了里面的方法二.Jackson序列化与反序列化关键函数1.1 readValue(Object obj)序列化函数分析1.单步调试ObjectMapper初始化过程,发现在com.fasterxml.jackson.databind.deser.BeanDeserializerFactory类下,存在一个HashSet<>集合,这里是定义了一个黑名单DEFAULT_NO_DESER_CLASS_NAMES(默认不反序列化的类)并且将该黑名单设置为unmodifiableSet(不可修改,若修改则抛出异常)。
2.继续跟进,回到主程序,进入enableDefaultTyping(),这是一个Jackson在序列化和反序列化时配置的项目,当ObjectMapper对象调用该函数时,那么OBJECT_AND_NON_CONCRETE就会生效,导致需要json字符串包含类名来反序列化。
且接收封装的数组形式:[“...”,{“...”:“...”}]3.writeValueAsString(Object value)跟踪value参数,在_configAndWriteValue()函数中会判断该value对象是否是可关闭资源,如果是,则进入_configAndWriteCloseable(),对value强制转换,防止意外异常发生。
如果不是,则直接进入serializeValue()4.进入serializeValue(),通过反射获取value的Class对象5.跟踪cls参数流向,进入typedValueSerializer()6.到这里就已经很明显了,获取对象的hash值,通过该hash值从HashMap 内获取JsonSerializer<Object>对象,并返回,且此处加了synchronized(重量级锁,与本文无关,不做赘述),进行线程同步。
因为此时HashMap里面为空,因此回到findTypedValueSerializer()继续判断ser。
这里也就是Jackson通过维护一个HashMap用对象hash值来获取序列化对象。
该序列化对象是Json串内指定的类,该序列化对象可以遍历原类的所有方法。
7.继续跟进,进入_addFields(),implName是代表类属性名,从findImplicitPropertyName()内获取该函数接收的参数为[field com.caucho.config.types.ResourceRef#_location]这个参数是从AnnotatedMember类的getFullName()获取代码含义前文已有描述。
8.进入findImplicitPropertyName()函数,再次进入_findConstructorName(),并携带[field com.caucho.config.types.ResourceRef#_location]发现_findConstructorName()函数下有一个类型判断,该类型判断是判断进入的参数是否是AnnotatedParameter对象实例,通过观察代码,发现AnnotatedParameter继承自AnnotatedMember,而进入的参数是AnnotatedMember 类型,因此参数是其父类对象实例,根据JA V A多态规则,该参数显然不能是子类对象实例,而之所以参数可以传进来,是因为Annotated是AnnotatedMember 的父类,也就是向下转型合理,向上转型是不可以的。
该函数执行结果为null。
9.回到_addFields()(该函数主要目的是为了遍历Json串对象下的所有字段属性名以及对该属性名的一些判断)函数,继续往下跟进,发现implName通过getName()获取到字段名_location继续向下,进入hasIgnoreMarker()这里是判断字段是否被标记为可忽略,可以忽略的话就不会严格按照json串来映射对象,通俗的说就是Json串里面可以有对象所不包含的字段。
继续判断该字段是否被声明为transient(JA V A中添加该属性,则字段不会被序列化)。
10.继续跟进,断点到build()函数,经过几次遍历上文提到的HashMap,此时field字段值如下,这是由FieldBuilder()创建的,这是类内字段属性的完整表示。
private ng.String com.caucho.config.types.ResourceGroupCo nfig._lookupName11.所序列化的类中有多少字段就会遍历多少次,且所遍历到的字段都会存入一个POJOPropertyBuilder中,如下图props中保存了字段的许多属性。
且这些字段,会先从父类开始遍历,再遍历子类,以下是ResourceRef 和ResourceGroupConfig的所有字段12.属性字段收集完成之后,回到collectAll()函数,再次进行收集方法的过程13.进入_addMethods()函数,首先memberMethods会遍历所有的成员方法。