일상/레벨업 독서

[이펙티브 자바] Item 85 자바 직렬화의 대안을 찾으라.

Gamii 2022. 6. 21. 19:13
728x90
핵심 정리

직렬화는 위험하니 피해야 한다. 시스템을 밑바닥부터 설계한다면 JSON이나 프로토콜 버퍼 같은 대안을 사용하자. 신뢰할 수 없는 데이터는 역직렬화하지 말자. 꼭 해야 한다면 객체 역직렬화 필터링을 사용하되, 이 마저도 모든 공격을 막아줄 수는 없음을 기억하자. 클래스가 직렬화를 지원하도록 만들지 말고, 꼭 그렇게 만들어야 한다면 정말 신경써서 작성해야 한다.

 

 

직렬화란?

 

넓은 의미로 직렬화는 어떤 데이터를 다른 데이터의 형태로 변환하는 것이다.

이팩티브 자바에서 말하는 직렬화(Serializable)란 바이트 스트림으로의 직렬화로 객체의 상태를 바이트 스트림으로 변환하는 것이고, 반대로 바이트 스트림에서 객체의 상태로 변환하는 건 역직렬화(Deserializable)이다.

 

 

 

직렬화의 근본적인 문제

 

직렬화를 하고 나서 역직렬화 할 때 문제가 된다. ObjectInputStream의 readObject 메서드를 호출하면서 객체 그래프가 역직렬화되기 때문이다. readObject 메서드는 클래스패스 안의 거의 모든 타입의 객체를 만들어 낼 수 있는 생성자이다. 바이트 스트림을 역직렬화하는 과정에서 이 메서드는 그 타입들 안의 모든 코드를 수행할 수 있다. 이 말인즉슨, 그 타입들의 코드 전체가 공격 범위에 들어간다는 뜻이다.

바이트 스트림으로 직렬화하는데 시간이 별로 걸리지 않지만 역직렬화를 잘못하면 시간이 오래걸린다.

 

 

 

직렬화 위험을 회피하는 가장 좋은 방법은 아무것도 역직렬화하지 않는 것

애초에 신뢰할 수 없는 바이트 스트림을 역직렬화하는 일 자체가 스스로를 공격에 노출하는 행위이다. 여러분이 작성하는 새로운 시스템에서 자바 직렬화를 써야 할 이유는 전혀 없다. 객체와 바이트 시퀀스를 변환해주는 다른 매커니즘이 많이 있다.

 

 

 

 

크로스-플랫폼 구조화된 데이터 표현(cross-platform structured-data representation)

1. JSON

  • 브라우저와 서버의 통신용으로 설계
  • 자바스크립트용
  • 텍스트 기반으로 사람이 읽을 수 있고, 오직 데이터를 표현하는 데 쓰임

2. 프로토콜 버퍼(Protocol Buffers, protobuf)

  • 구글이 서버 사이에 데이터를 교환하고 저장하기 위해 설계
  • C++용
  • 문서를 위한 스키마(타입)를 제공하고 올바로 쓰도록 가용한다.

 

 

 

역직렬화한 데이터가 안전한지 완전히 확신할 수 없다면 객체 역직렬화 필터링(java.io.ObjectInputFilter)을 사용하자.

자바 9에 추가 되었고, 이전 버전에서도 쓸 수 있도록 이식되었다. 객체 역직렬화 필터링은 데이터 스트림이 역직렬화되기 전에 필터를 설치하는 기능이다. 클래스 단위로, 특정 클래스를 받아들이거나 거부할 수 있다.