JAVA序列化对象
对敏感字段加密
1. 情境:服务器端给客户端发送序列化对象数据,对象中有一些数据是敏感的,比如密码字符串等,希望对该密码字段在序列化时,
进行加密,而客户端如果拥有解密的密钥,只有在客户端进行反序列化时,才可以对密码进行读取,这样可以一定程度保证序列化对象的数据安全。
2. 解决:在序列化过程中,虚拟机会试图调用对象类里的 writeObject 和 readObject 方法,进行用户自定义的序列化和反序列化,
如果没有这样的方法,则默认调用是 ObjectOutputStream 的 defaultWriteObject 方法以及 ObjectInputStream 的 defaultReadObject 方法
。用户自定义的 writeObject 和 readObject 方法可以允许用户控制序列化的过程,比如可以在序列化的过程中动态改变序列化的数值。
基于这个原理,可以在实际应用中得到使用,用于敏感字段的加密工作,清单 3 展示了这个过程
注:writeObject/readObject这两个方法为private ObjectOutputStream使用了反射来寻找是否声明了这两个方法。
因为ObjectOutputStream使用getPrivateMethod,所以这些方法不得不被声明为private以至于供ObjectOutputStream来使用。
package com.king.test;
import java.io.*;
public class A implements Serializable{
private static final long serialVersionUID = 1L;
private int age;
private String pass;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPass() {
return pass;
}
public A setPass(String pass) {
this.pass = pass;
return this;
}
private void writeObject(ObjectOutputStream out){
try{
ObjectOutputStream.PutField putField = out.putFields();
System.out.println("原始密码:"+pass);
pass = "jiami";
putField.put("pass",pass);
System.out.println("加密后:"+pass);
out.writeFields();
} catch (Exception e){
e.printStackTrace();
}
}
private void readObject(ObjectInputStream in){
try{
ObjectInputStream.GetField getField = in.readFields();
Object opass = getField.get("pass","");
System.out.println("需要解密的字符串:"+opass.toString());
pass = "passjiami";
} catch (Exception e){
e.printStackTrace();
}
}
}
public class MyTest implements Serializable{
private static final long serialVersionUID = 1L;
public static int staticVar = 5;
@Test
public void test(){
try{
A a = new A();
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("D:\\result.obj"));
out.writeObject(a);
out.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream("D:\\result.obj"));
a = (A)in.readObject();
System.out.println(a.getPass());
in.close();
} catch (Exception e){
e.printStackTrace();
}
}
}