代码混淆与JSON数据序列化问题

 Java代码混淆和JSON数据序列化问题

 基本观点:

 第一点:Java代码生成的Jar文件很容易被反编译,常用工具JD-GUI(http://jd.benow.ca/)

 第二点:Jar文件常用的“加密”方式是混淆(有专门的混淆软件,有些需要收费的),使得类名、类中字段和方法名称等难以肉眼判断。例如

 

第三点:JSON协议使用方便,非常流行。常用框架由于可以使用自定义Model类,直接转换成JSON格式的数据,使用起来方便快捷。我使用的alibaba的fastjson.jar。(吐槽一下:虽然该包有不少bug需要进一步完善,整体已经相当不错了。) 例如:

 基本的Model

public 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;
	}
}

 

 测试:

import com.alibaba.fastjson.JSONObject;

public class Test {

	public static void main(String[] args) {
		String json = JSONObject.toJSONString(new User("wsc", 25));
		System.out.println(json);
		User user = JSONObject.parseObject(json, User.class);
		System.out.println(user.getAge());
		System.out.println(user.getName());
	}
}

 

  打印:

{"age":25,"name":"wsc"}
25
wsc

第四点:

当使用框架转换Model为String类型的JSON数据时,通常是根据Model的set和get方法获取需要保存到磁盘的字段名称,常见手段是反射,如果直接获取Field,可能会产生很多,包括某些Field其实用户不想保存到磁盘transient字段或者中间变量字段,尽管fastjson.jar使用了字节码框架ASM来提高效率,也是需要通过set/get方法获取到字段名称。

问题:

如果使用了混淆,代码中字段和方法名称都被混淆,JavaBean的规则被改写,确实是能反序列化出对象,但是可能User名称已经被更改为AA,属性Name可能被更改为f.这个时候就会出现异常。

解决办法:

方法1:有些人推荐set和get方法不适用混淆,相当于Model的结构是公开的,虽然能够避免,总体不安全。

方法2:JSON序列化还有另外一种机制,Model是Map类型



 Map是直接获取字段名称的。
使用方法2的缺点是:当你反序列化的时候,如果你的Model里字段类型是自定义类对象,比如User对象中Age不是String,而是自定义类型Age,它是无法帮你自动反序列化成自定义对象Age的,需要手动创建。
 举例:

AppCheckBasic是一个基本Model,集成了JSONObject,由于JOSNObject本身是Map结构,所以AppCheckBasic也是一个Map。

AppCheckBasic有一个属性apps,它是List<AppBasic> 类型。

public class AppCheckBasic extends JSONObject {

	private static final long serialVersionUID = 1L;

	@SuppressWarnings("unchecked")
	public void initial() {
		// 把所有层次结构初始化
		List<AppBasic> apps = null;
		Object obj = this.get("apps");

		// 初始化赋值后使用
		if (obj instanceof ArrayList) {
			apps = (List<AppBasic>) obj;
		}
		// 反序列化(非第一次初始化后)
		if (obj instanceof JSONArray) {
			JSONArray array = (JSONArray) this.get("apps");
			apps = new ArrayList<AppBasic>();
			for (int i = 0; i < array.size(); i++) {
				// AppBasic内部没有"复杂"数据类型
				AppBasic appBasic = JSON.parseObject(array.getString(i),
						AppBasic.class);
				apps.add(appBasic);
			}
		}

		// 初始化内容
		this.put("apps", apps);
	}

	// set和get方法是为了方便
	@SuppressWarnings("unchecked")
	public List<AppBasic> getApps() {
		List<AppBasic> apps = (List<AppBasic>) this.get("apps");
		return apps;
	}

	public void setApps(List<AppBasic> apps) {
		this.put("apps", apps);
	}

}

 除了必须手动反序列化重建自定义对象或者复杂对象如List等,为了方便为该Map类型的Bean定义set和get方法。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值