1997년 처음 직렬화가 도입되었으나 추후 어마어마하게 문제가 많다는 것이 밝혀졌다.
결론 부터 말하자면
자바 시스템 내부에서 사용되는 객체 또는 데이터를 외부의 자바 시스템에서도 사용할 수 있도록 바이트(byte) 형태로 데이터 변환하는 기술
각자 PC의 OS마다 서로 다른 가상 메모리 주소 공간을 갖기 때문에, Reference Type의 데이터들은 인스턴스를 전달 할 수 없다.
따라서, 이런 문제를 해결하기 위해선 주소값이 아닌 Byte 형태로 직렬화된 객체 데이터를 전달해야 한다.
직렬화된 데이터들은 모두 Primitive Type(기본형)이 되고, 이는 파일 저장이나 네트워크 전송 시 파싱이 가능한 유의미한 데이터가 된다. 따라서, 전송 및 저장이 가능한 데이터로 만들어주는 것이 바로 '직렬화(Serialization)'이라고 말할 수 있다.
자바에서는 간단히 java.io.Serializable
인터페이스 구현으로 직렬화/역직렬화가 가능하다.
역직렬화는 직렬화된 데이터를 받는쪽에서 다시 객체 데이터로 변환하기 위한 작업을 말한다.
직렬화 대상 : 인터페이스 상속 받은 객체, Primitive 타입의 데이터
Primitive 타입이 아닌 Reference 타입처럼 주소값을 지닌 객체들은 바이트로 변환하기 위해 Serializable 인터페이스를 구현해야 한다.
직렬화는 프로그래머가 어렵지 않게 분산 객체를 만들 수 있다는 구호는 매력적이지만, 보이지 않는 생성자, API 와 구현 상의 모호해진 경계, 잠재적인 정확성 문제, 성능, 보안, 유지보수성 등 대가가 크다
직렬화를 하고 나서 역직렬화를 할 때 문제가 됩니다.
자바의 표준 라이브러리나 아파치 커먼즈 컬렉션 같은 서드파티 라이브러리는 물론 애플리케이션 자신의 클래스들도 공격 범위에 포함된다.
역직렬화 과정에서 호출되어 잠재적으로 위험한 동작을 수행하는 메서드들을 가젯(gadget) 이라고 부르는데, 가젝 체인으로 보안공격이 가능하다.
역직렬화에 시간이 오래 걸리는 짧은 스트림을 역직렬화하는 것만으로도 서비스 거부 공격에 쉽게 노출될 수 있다. 이런 스트림을 역직렬화 폭탄(descerialization bomb) 라고 부른다.
static byte[] bomb() {
Set<Object> root = new HashSet<>();
Set<Object> s1 = root;
Set<Object> s2 = new HashSet<>();
for (int i = 0; i < 100; i++) {
Set<Object> t1 = new HashSet<>();
Set<Object> t2 = new HashSet<>();
t1.add("foo");
s1.add(t1);
s1.add(t2);
s2.add(t1);
s2.add(t2);
s1 = t1;
s2 = t2;
}
return serialize(root); // 직렬화 수행
}
serialize 메서드가 수행되기 전의 인스턴스의 참조 형태를 보면 아래와 같은 형태다. 이 깊이가 100단계까지 만들어진다. 즉, 이를 역직렬화하려면 hashCode 메서드를 2^100 번 넘게 호출해야 한다.