item 85) 자바 직렬화의 대안을 찾으라

직렬화

개념

  • 자바 시스템 내부에서 사용되는 객체 또는 데이터를 외부의 자바 시스템에서도 사용할 수 있도록 바이트(byte) 형태로 데이터 변환하는 기술과 바이트로 변환된 데이터를 다시 객체로 변환하는 기술(역직렬화)을 아우르는 것

  • 시스템적으로 보면, JVM의 메모리에 상주(힙 또는 스택)되어 있는 객체 데이터를 바이트 형태로 변환하는 기술과, 직렬화된 바이트 형태의 데이터를 객체로 변환해서 JVM으로 상주시키는 형태를 이야기한다.

사용하는 이유

  • 자바 시스템 개발에 최적화되어있어 복잡한 데이터 구조의 클래스의 객체라도 직렬화 기본 조건만 지키면 큰 작업 없이 바로 직렬화/역직렬화 가능하다.

  • 데이터 타입이 자동으로 맞춰지기 때문에 이 부분에 대해 신경을 쓰지 않아도 된다.

  • 프레임워크를 사용하지 않는 경우에는 CSV, JSON을 사용하는 것보다 편할 것 같다.

직렬화의 문제점

  • 공격 범위가 너무 넓고, 지속적으로 더 넓어지기 때문에 방어하기 어렵다

  • readObject() 메서드는 Serializable 인터페이스를 구현한 클래스패스 안에 거의 모든 타입의 객체를 만들어 낼 수 있다. 바이트 스트림을 역직렬화하는 과정에서 이 메서드는 그 타입들 안의 모든 코드를 수행할 수 있고, 이로 인해 그 타입들의 코드 전체가 공격 범위에 들어가게 된다. (자바 표준 라이브러리와 서드 파티 라이브러리 등 모두 포함)

  • 여러 가젯 메서드를 사용해 가젯 체인을 구성할 수 있으며, 강력한 가젯 체인은 시스템을 마비시키고 그로 인해 막대한 피해를 볼 수 있다.

    가젯 메서드: 역직렬화 과정에서 호출되어 잠재적으로 위험한 동작을 수행하는 메서드

역직렬화 폭탄

  • 역직렬화에 시간이 오래 걸리는 짧은 스트림을 역직렬화하는 스트림

  • 아래 예시는 바이트 스트림으로 직렬화하는데는 시간이 별로 걸리지 않지만, 역직렬화시 hashCode 메서드를 2^100번 넘게 호출해야 하므로 영원히 계속된다.

  • 여러 객체를 생성한다면 스택 깊이 제한에 걸려 프로그램에 장애가 발생할 것이다.

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("f"); // t1: {"f"}, t2: {}
        s1.add(t1); s1.add(t2); // s1:{{"f"}, {}}, root:{{"f"}, {}}

        s2.add(t1); s2.add(t2); // s2:{{"f"}, {}}
        s1 = t1; s2 = t2; // s1:{"f"}, s2: {}, root:{{"f"}, {}}
    }
    return serialize(root);
}

해결 방안

  • 새로운 시스템에는 객체와 바이트 시퀀스를 변환해주는 다른 메커니즘이 많이 있기 때문에 직렬화 사용을 자제하는 것이 좋다.

  • 신뢰할 수 없는 데이터는 절대 역직렬화하면 안된다. (역직렬화 폭탄)

크로스-플랫폼 구조화된 데이터 표현

cross-platform structured-data representation

  • 자바 직렬화와 다른 메커니즘을 가진 객체와 바이트 시퀀스 변환 시스템

  • 자바 직렬화의 위험성이 없으며 훨씬 간단하다.

  • 다양한 플랫폼 지원, 우수한 성능, 풍부한 지원 도구 등을 제공

  • 속성-값 쌍의 집합으로 구성된 간단하고 구조화된 데이터 객체를 사용

  • JSON

    • 텍스트 기반 표현에 효과적이고 사람이 읽을 수 있다

  • 프로토콜 버퍼

    • 문서를 위한 스키마를 제공하며 효율이 좋다

역직렬화 필터링

  • 데이터 스트림이 역직렬화되기 전에 필터를 설치하는 기능

  • 블랙리스트에 기록된 클래스를 거부하거나, 화이트리스트에 기록된 클래스만 수용한다.

  • 이미 알려진 위험으로부터만 보호할 수 있는 블랙리스트보다 화이트리스트를 사용하는 것이 좋다.

  • 메모리를 과하게 사용하거나 객체 그래프가 너무 깊어지는 상황으로부터 보호한다.

  • 역직렬화 폭탄은 걸러내지 못한다.

출처

Last updated