Java/EffectiveJava

Effective Java Item85. 자바 직렬화의 대안을 찾으라.

Flambee 2025. 3. 23. 22:15

자바 직렬화

  • 분산 객체를 만들 수 있다는 구호
  • 보이지 않는 생성자, API와 구현 사이의 모호해진 경계, 잠재적인 정확성 문제, 성능, 보안, 유지보수성 등 대가가 컸다.

직렬화의 근본적인 문제

  • 공격 범위가 너무 넓고 지속적으로 더 넓어져 방어하기 어렵다.
  • ObjectInputStream의 readObject 메서드를 호출하면서 객체 그래프가 역직렬화되기 때문이다.
    • readObject 메서드는 클래스패스 안의 거의 모든 타입의 객체를 만들어 낼 수 있는 생성자다.
    • 바이트 스트림을 역직렬화하는 과정에서 이 메서드는 그 타입들 안의 모든 코드를 수행할 수 있다.
    • 코드 전체가 공격 범위에 들어간다.
  • 모든 직렬화 가능 클래스들을 공격에 대비하도록 작성한다해도 취약하다.

역직렬화에 시간이 오래 걸리는 짧은 스트림을 역직렬화하는 것만으로도 서비스 거부 공격에 쉽게 노출될 수 있다.

직렬화 위험을 회피하는 가장 좋은 방법은 아무것도 역직렬화하지 않는 것이다. 즉, 새로운 시스템에서 자바 직렬화를 써야 할 이유는 없다.

방법 중에 하나는 객체와 바이트 시퀀스를 변환해주는 다른 메카니즘을 사용하는 것이다. 다양한 플랫폼 지원, 우수한 성능, 풍부한 지원 도구, 활발한 커뮤니티와 전문가 집단 등 수많은 이점까지 제공한다.

임의의 객체 그래프를 자동으로 직렬화/역직렬화하지 않고, 속성-값 쌍의 집합으로 구성된 간단하고 구조화된 데이터 객체를 사용한다.

대표적인 방법은 JSON과 프로토콜 버퍼를 사용하는 것이다.

JSON

  • 텍스트 기반이라 사람이 읽을 수 있다.

프로토콜 버퍼

  • 이진 표현으로 효율적이다.
  • 문서를 위한 스키마를 제공하고 올바르게 쓰도록 강요한다.
  • 텍스트 표현(pbtxt)도 지원한다.

레거시 시스템 때문에 자바 직렬화를 완전히 배제할 수 없을 때는 신뢰할 수 없는 데이터는 절대 역직렬화하지 않는 것이다.

직렬화를 피할 수 없고 역직렬화한 데이터가 안전하지 확신할 수 없다면 객체 역직렬화 필터링(java.io.ObjectInputFilter)을 사용하자 객체 역직렬화 필터링은 데이터 스트림이 역직렬화되기 전에 필터를 설치하는 기능이다. 클래스 단위로, 특정 클래스를 받아들이거나 거부할 수 있다.

  • 기본 수용 모드 : 블랙리스트에 기록된 잠재적으로 위험한 클래스들을 거부한다.
  • 기본 거부 모드 : 화이트리스트에 기록된 안전하다고 알려진 클래스들만 수용한다.

자바 직렬화를 사용하는 시스템을 관리해야 한다면 시간과 노력을 들여서라도 JSON, 프로토콜 버퍼와 같은 데이터 표현으로 마이그레이션하도록 하자.