Item 85. Java 직렬화의 대안을 찾으라
직렬화, 역직렬화
- 직렬화 : Java가 객체를 byte stream으로 인코딩
- 역직렬화 : byte stream을 객체로 encoding
역직렬화와 보안간의 관련성
직렬화의 근본적인 문제는 공격범위가 넓다는 점이다. ObjectInputStream의 readObject method를 호출하면 객체 그래프가 역직렬화되기 때문이다.
클래스패스 안의 Serilizable interface를 구현한 거의 모든 타입의 객체를 만들어낼 수 있기 떄문에, 바이트 스트림을 역직렬화하는 과정에서 이 method는 그 타입들 안의 모든 코드를 수행할 수 있다.-> 그 타입들의 코드 전체가 공격범위에 들어간다.
gadget method : 객체 역직렬화 과정에서 호출되어 잠재적으로 위험한 동작을 수행하는 method
따라서 위험요소가 없는 byte stream만 역직렬화해야 한다.
그렇다하더라도 역직렬화에 시간이 오래걸리는 짧은 stream을 역직렬화 하는 것만으로도 서비스 거부 공격(denial-of-service,DoS)을 할 수 있다.
1 | static byte[] bomb(){ |
위 코드는 201개의 HashSet 객체를 만드는데, 각각은 3개 이하의 객체 참조를 가진다. HashSet을 역직렬화하려면 각각 원소의 해시코드를 계산해야 하는데,
HashSet에 포함된 객체 참조 타입이 역시 HashSet임으로 depth가 100단계까지 만들어진다. 즉 2^100 이상으로 HashCode method를 호출해야 한다.
역직렬화의 보안성 이슈를 피하는 방법
- 저자는 역직렬화 자체를 하지 않을 것을 권고하고 있다. 직렬화 대신에 객체를 byte sequence로 바꿔주는 mechanism (cross-platform structured-data representation)을 사용하자
- 만약 직렬화를 피할수 없는 상황이고, 역직렬화한 데이터가 안전한지 완전히 확신할 수 없다면, 객체 역직렬화 필터링 (java.io.ObjectInputFilter)을 사용하자
이 기능은 data stream이 역직렬화되기 전에 필터를 설치하는 기능이다. 클래스 단위로 특정 클래스를 받아들어거나 거부할 수 있는데, 저자는 블랙 리스트 방식보다는 안전하다고 알려진 클래스만 허용하는 화이트 리스트 방식을 사용할 것을 권고하고 있다.
Cross-platform structured-data representation
- 객체를 byte sequence 로 바꿔주는 메카니즘
- 객체 그래프는 직렬화 / 역직렬화하지 않고, 간단한 K-V형태의 객체를 사용한다.
- 대표적인 예시로 JSON과 protocol buffer가 있다.
- JSON은 텍스트 기반이라 사람이 읽을 수 있고, Protocol buffer는 이진 표현이라 효율이 높다.