cleanUrl: /posts/consider-serialization-proxies-instead-of-serialized-instances
앞선 chapter 에서 버그와 보안 문제가 일어날 가능성이 있음을 확인하였는데 이 위험을 크게 줄일 방법이 serialization proxy pattern 이다.
private static
으로 class 를 선언한다.implements Serializable
를 붙여야 한다.Period
를 예시로 든다.
private static class SerializationProxy implements Serializable {
private static final long serialVersionUID = -2785633062946028119L;
private final Date start;
private final Date end;
SerializationProxy(Period period) {
start = period.start;
end = period.end;
}
}
이 다음에 외부 클래스(Period
)에 writeReplace
를 추가한다. 이건 그냥 복사해서 어디에서든지 사용해도 괜찮다.
private Object writeReplace() {
return new SerializationProxy(this);
}
목적은 Period
의 직렬화를 호출하면 결국 내부의 SerializationProxy
를 반환하는 역할을 한다.
직렬화가 이뤄지기 전에 바깥 클래스의 instance 를 직렬화 proxy 로 변환한다
writeReplace
때문에 직렬화 시스템은 결코 바깥 클래스의 직렬화 instance 를 생성할 수 없다.
다음의 readObject
를 바깥 클래스에 추가하면 공격자가 불변식을 훼손하고자 하는 시도 역시 막을 수 있다
// 직렬화 proxy pattern
private void readObject(ObjectInputStream stream) throws InvalidObjectException {
throw new InvalidObjectException("proxy 가 필요합니다");
}
마지막으로 바깥 클래스와 동일한 instance 를 반환하도록 readResolve
를 내부에 추가한다
private Object readResolve() {
return new Period(start, end);
}
이 method 드는 공개된 API 만을 사용해 바깥 클래스의 instace 를 생성한다.