Item 85. Alternatives Serialization

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

직렬화는 분산 객체를 손쉽게 만들 수 있게 해주지만, 심각한 보안 문제를 일으킬 수 있는 문제가 있다. 직렬화의 근본적인 문제는 공격 범위가 너무 넓고 지속적으로 넓어져 방어하기 어렵다는 점인데, 그 이유는 다음과 같다.

  1. ObjectInputStreamreadObject 메서드를 호출하여 객체를 역직렬화 수행

  2. 바이트 스트림을 역직렬화하는 과정에서 타입들 안의 모든 코드를 수행하게 됨

    • 원래 객체의 클래스 타입을 유지하면서 복원되며, 그 과정에서 해당 클래스의 코드가 실행

  3. 그 타입들의 코드 전체가 공격 범위에 포함하게 되어, 그 타입들의 코드가 악의적인 코드로 대체될 수 있음

또한, 역직렬화가 끝나지 않게 하는 역직렬화 폭탄(deserialization bomb)이라는 공격에도 노출될 수 있다.

class Test {

    static byte[] bomb() {
        Set<Object> root = new HashSet<>(); // 객체 그래프 루트
        Set<Object> s1 = root; // 루트에 대한 첫 번째 참조
        Set<Object> s2 = new HashSet<>(); // 루트와 독립적인 새로운 집합
        for (int i = 0; i < 100; i++) {
            // HashSet 객체 생성
            Set<Object> t1 = new HashSet<>();
            Set<Object> t2 = new HashSet<>();
            t1.add("foo");

            // s1에 t1, t2 추가
            s1.add(t1);
            s1.add(t2);
            // s2에 t1, t2 추가
            s2.add(t1);
            s2.add(t2);

            // s1, s2를 각각 t1, t2로 갱신
            s1 = t1;
            s2 = t2;
        }
        return serialize(root);
    }
}

위 코드를 수행하게 되면, 반복문에 의해 깊이가 100인 HashSet 객체가 생성되고, 이를 역직렬화하기 위해선 2^100번의 해싱 메서드를 호출해야 한다. 사실상 영원히 계속되는 작업을 수행하게 되며, 이를 감지하기 쉽지 않다는 문제도 존재한다.

이러한 문제를 해결하기 위해선 역직렬화 자체를 피하는 것이 가장 좋고, 필요하다면 직렬화 대신 다음과 같은 방법을 수행하는 것이 좋다.

  • 임의 객체 그래프를 직렬화/역직렬화 하는 대신, 속성-값 쌍의 집합으로 구성된 간단하고 구조화된 JSON 과 같은 데이터 표현을 사용

  • 만약 레거시 시스템으로 직렬화를 배제할 수 없는 경우, 신뢰할 수 없는 데이터는 절대 역직렬화하지 않는 것으로 한정

  • 역직렬화 필터링(ObjectInputFilter)을 사용할 땐 블랙리스트 대신 화이트리스트를 사용하여 필터링

Last updated

Was this helpful?