扫码领资料
获网安教程
本文由掌控安全学院 - nn0nkey 投稿
来Track安全社区投稿~
千元稿费!还有保底奖励~(https://bbs.zkaq.cn)
前言
fastjson
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.24</version>
</dependency>
JACKSON
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.9</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.7.9</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.7.9</version>
</dependency>
import com.fasterxml.jackson.databind.ObjectMapper;
public class Example {
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
User user = new User("John", 30);
String json = objectMapper.writeValueAsString(user);
System.out.println(json);
String jsonInput = "{"name":"John","age":30}";
User deserializedUser = objectMapper.readValue(jsonInput, User.class);
System.out.println(deserializedUser.getName());
}
}
class User {
private String name;
private int age;
public User() {}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
{"name":"John","age":30}
John
为什么需要了解底层
底层调试分析
调试代码
package demo2;
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
package demo2;
import com.alibaba.fastjson.JSON;
public class FastjsonTest {
public static void main(String[] args) {
Person person = new Person("LJL", 18);
String jsonString = JSON.toJSONString(person);//当然还有很多方法,这个不重要
System.out.println(jsonString);
}
}
过程分析
public static String toJSONString(Object object) {
return toJSONString(object, emptyFilters);
}
public static String toJSONString(Object object, SerializerFeature... features) {
return toJSONString(object, DEFAULT_GENERATE_FEATURE, features);
}
public enum SerializerFeature {
QuoteFieldNames,
UseSingleQuotes,
WriteMapNullValue,
WriteEnumUsingToString,
WriteEnumUsingName,
UseISO8601DateFormat,
WriteNullListAsEmpty,
WriteNullStringAsEmpty,
WriteNullNumberAsZero,
WriteNullBooleanAsFalse,
SkipTransientField,
SortField
.....//很多不举了
}
static final SerializeFilter[] emptyFilters = new SerializeFilter[0];
public interface SerializeFilter {
}
public static String toJSONString(Object object, SerializeConfig config, SerializeFilter[] filters, String dateFormat, int defaultFeatures, SerializerFeature... features) {
SerializeWriter out = new SerializeWriter((Writer)null, defaultFeatures, features);
String var15;
try {
JSONSerializer serializer = new JSONSerializer(out, config);
if (dateFormat != null && dateFormat.length() != 0) {
serializer.setDateFormat(dateFormat);
serializer.config(SerializerFeature.WriteDateUseDateFormat, true);
}
if (filters != null) {
SerializeFilter[] var8 = filters;
int var9 = filters.length;
for(int var10 = 0; var10 beforeFilters = null;
protected List afterFilters = null;
protected List propertyFilters = null;
protected List valueFilters = null;
protected List nameFilters = null;
protected List propertyPreFilters = null;
protected List labelFilters = null;
.......很多
然后就是获得的方法比如
public List getBeforeFilters() {
if (this.beforeFilters == null) {
this.beforeFilters = new ArrayList();
this.writeDirect = false;
}
就是你自己可以定义
Fastjson
的序列化行为。public enum SerializerFeature {
QuoteFieldNames,
/**
*
*/
UseSingleQuotes,
/**
*
*/
WriteMapNullValue,
/**
* 用枚举toString()值输出
*/
WriteEnumUsingToString,
/**
* 用枚举name()输出
*/
WriteEnumUsingName,
/**
*
*/
UseISO8601DateFormat,
/**
* @since 1.1
*/
WriteNullListAsEmpty,
.....很多
serializeConfig.putFeature(SerializerFeature.WriteMapNullValue); // 输出值为null的字段
serializeConfig.putFeature(SerializerFeature.WriteNullListAsEmpty); // 输出列表为null时写为[]
SerializeWriter
可以将 Java 对象序列化为 JSON 格式的字符串。它支持多种数据类型的序列化,包括基本数据类型、字符串、数组、列表、地图等。SerializeWriter
允许你控制输出的 JSON 字符串的格式,例如是否缩进、是否换行等。SerializeWriter
,你可以注册自定义的序列化器,以改变默认的序列化行为。这允许你为特定的类或全局配置序列化策略。JSONSerializer
是一个用于将 Java 对象序列化为 JSON 字符串的类。 回到正题public static String toJSONString(Object object, //
SerializeConfig config, //
SerializeFilter[] filters, //
String dateFormat, //
int defaultFeatures, //
SerializerFeature... features) {
SerializeWriter out = new SerializeWriter(null, defaultFeatures, features);
try {
JSONSerializer serializer = new JSONSerializer(out, config);//获取序列化对象的实例
if (dateFormat != null && dateFormat.length() != 0) {
serializer.setDateFormat(dateFormat);//设置我们的数据形式,因为dataFormat为空,默认
serializer.config(SerializerFeature.WriteDateUseDateFormat, true);//设置我们数据的特点,就是前面讲的各种feature
}
if (filters != null) {
for (SerializeFilter filter : filters) {
serializer.addFilter(filter);
}
}//如果我们filter不是空,循环获取我们的filter,增加进我们的序列化里面
serializer.write(object);写入我们的序列化对象,就是person
return out.toString();
} finally {
out.close();
}
}
public final void write(Object object) {
if (object == null) {
out.writeNull();
return;
}
Class<?> clazz = object.getClass();//获取到person的class
ObjectSerializer writer = getObjectWriter(clazz);//获取对象的writer
try {
writer.write(this, object, null, null, 0);
} catch (IOException e) {
throw new JSONException(e.getMessage(), e);
}
}
public ObjectSerializer getObjectWriter(Class<?> clazz) {
return config.getObjectWriter(clazz);
}
if (create) {
put(clazz, createJavaBeanSerializer(clazz));
}
private final ObjectSerializer createJavaBeanSerializer(Class<?> clazz) {
SerializeBeanInfo beanInfo = TypeUtils.buildBeanInfo(clazz, null, propertyNamingStrategy);
if (beanInfo.fields.length == 0 && Iterable.class.isAssignableFrom(clazz)) {
return MiscCodec.instance;
}
return createJavaBeanSerializer(beanInfo);
}
public static SerializeBeanInfo buildBeanInfo(Class<?> beanType //
, Map aliasMap //
, PropertyNamingStrategy propertyNamingStrategy) {
JSONType jsonType = beanType.getAnnotation(JSONType.class);//值为null,因为person根本没有注解
Map fieldCacheMap = new HashMap();//创建一个map
ParserConfig.parserAllFieldToCache(beanType, fieldCacheMap);//把beanType的field(name,age)都装进fieldCacheMap
List fieldInfoList = computeGetters(beanType, jsonType, aliasMap, fieldCacheMap, false, propertyNamingStrategy);/使用computeGetters方法创建一个列表,这个方法会获取一堆东西,然后对获取到的进行判断,再获取一堆东西,见p1
FieldInfo[] fields = new FieldInfo[fieldInfoList.size()];
fieldInfoList.toArray(fields);
String[] orders = null;//定义为null,下面会用到
final int features;
String typeName = null;
if (jsonType != null) {
orders = jsonType.orders();
typeName = jsonType.typeName();
if (typeName.length() == 0) {
typeName = null;
}
features = SerializerFeature.of(jsonType.serialzeFeatures());
} else {
features = 0;
}
FieldInfo[] sortedFields;
List sortedFieldList;
if (orders != null && orders.length != 0) {
sortedFieldList = TypeUtils.computeGetters(beanType, jsonType, aliasMap,fieldCacheMap, true, propertyNamingStrategy);
} else {
sortedFieldList = new ArrayList(fieldInfoList);
Collections.sort(sortedFieldList);
}//又创建了一个list,不过是sortlist,会进行排序,排序规则具体在sort方法里面
sortedFields = new FieldInfo[sortedFieldList.size()];
//然后就是创建一个sortedFields
sortedFieldList.toArray(sortedFields);
if (Arrays.equals(sortedFields, fields)) {
sortedFields = fields;
}//进行判断他们是否一样,是不一样的,因为他们的顺序不一样,具体见p2
return new SerializeBeanInfo(beanType, jsonType, typeName, features, fields, sortedFields);//然后就是返回一个SerializeBeanInfo,包含着一些东西见p3
}
public ObjectSerializer createJavaBeanSerializer(SerializeBeanInfo beanInfo) {
JSONType jsonType = beanInfo.jsonType;//还是为null,if不进入
if (jsonType != null) {
Class<?> serializerClass = jsonType.serializer();
if (serializerClass != Void.class) {
try {
Object seralizer = serializerClass.newInstance();
if (seralizer instanceof ObjectSerializer) {
return (ObjectSerializer) seralizer;
}
} catch (Throwable e) {
// skip
}
}
if (jsonType.asm() == false) {
asm = false;
}
}
Class<?> clazz = beanInfo.beanType;//获取person的class
if (!Modifier.isPublic(beanInfo.beanType.getModifiers())) {//检查beanInfo.beanType修饰是不是public getModifiers获取修饰符 因为是public跳过
return new JavaBeanSerializer(beanInfo);
}
boolean asm = this.asm; //asm为ture
if (asm && asmFactory.classLoader.isExternalClass(clazz)//使用asmFactory创建的类加载器来判断clazz是否是由其他应用程序或JVM加载器加载的外部类。见p1 所以跳过if
|| clazz == Serializable.class || clazz == Object.class) {
asm = false;
}
if (asm && !ASMUtils.checkName(clazz.getSimpleName())) {
asm = false;
}
//遍历字段,看看有没有JSONField注解,有的话进一步检查,看看能不能被asm处理
if (asm) {
for(FieldInfo field : beanInfo.fields){
JSONField annotation = field.getAnnotation();
if (annotation == null) {
continue;
}
if ((!ASMUtils.checkName(annotation.name())) //
|| annotation.format().length() != 0
|| annotation.jsonDirect()
|| annotation.serializeUsing() != Void.class
) {
asm = false;
break;
}
}
}
if (asm) {//如果所有字段都适合使用ASM,代码将尝试创建一个ObjectSerializer
try {
ObjectSerializer asmSerializer = createASMSerializer(beanInfo);
if (asmSerializer != null) {
return asmSerializer;
}
} catch (ClassFormatError e) {
// skip
} catch (ClassCastException e) {
// skip
} catch (Throwable e) {
throw new JSONException("create asm serializer error, class "
+ clazz, e);
}
}
return new JavaBeanSerializer(beanInfo);
}
public boolean isAsmEnable() {
return asm;
}
public void setAsmEnable(boolean asmEnable) {
if (ASMUtils.IS_ANDROID) {
return;
}
this.asm = asmEnable;
}
public static SerializeConfig getGlobalInstance() {
return globalInstance;
}
public SerializeConfig() {
this(1024);
}
public boolean isExternalClass(Class<?> clazz) {
ClassLoader classLoader = clazz.getClassLoader();
if (classLoader == null) {
return false;
}//我们的person是已经被加载过,所以可以获得它的类加载器为AppClassLoader
总结
申明:本公众号所分享内容仅用于网络安全技术讨论,切勿用于违法途径,
所有渗透都需获取授权,违者后果自行承担,与本号及作者无关,请谨记守法.
没看够~?欢迎关注!
分享本文到朋友圈,可以凭截图找老师领取
上千教程+工具+靶场账号哦
分享后扫码加我!
回顾往期内容
代理池工具撰写 | 只有无尽的跳转,没有封禁的IP!
点赞+在看支持一下吧~感谢看官老爷~
你的点赞是我更新的动力
原文始发于微信公众号(进击的HACK):javasec | fastjson底层分析
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论