자바 직렬화의 대안을 찾으라
자바 직렬화는 공격범위가 넓어 악의적으로 공격할 수 있는 요소가 많아
직렬화 사용을 주의해야한다.
직렬화를 사용하려면 자바 9 부터 추가 된 직렬화 필터 사용을 하자
허용된 클래스에만 역직렬화를 사용 할 수 있어서 더 안전하게 사용할수있다.
Serializable을 구현할지는 신중히 결정하라
Serializable 를 구현 하는 순간 직렬화 가능한 클래스가 되지만,
릴리즈 후 변경이 힘들어진다
클래스의 내부 구현을 수정하면 직렬화 형태가 달라진다.
새로 변경된 클래스를 이전 버전에서 역직렬화 하게 되면 에러가 발생한다.
(SerialVersionUID를 생성해두지 않으면 시스템이 런타임에 자동으로 생성하는데, 이 값이 객체가 변경이 되면 자동으로 변경이 되어버려서 버전이 다른 곳에서 역직렬화를 하면 문제가 발생한다.
SerialVersionUID 를 명시적으로 적어주자)
버그와 보안에도 취약해지고
새로운 릴리즈 마다 테스트 할게 많아진다.
Serializable 을 사용하면 안되는 곳은
상속 목적으로 설계된 클래스와 대부분의 인터페이스 그리고 내부 클래스가 있다.
클래스를 확장하면 위험성을 그대로 하위 클래스에도 전파하는 것이다.
만약 직렬화와 확장이 모두 가능한 클래스를 만들면, 하위 클래스에서 재정의 할 수 없게
final 키워드를 붙이자.
커스텀 직렬화 형태를 고려해보라
Serializable 을 통해 직렬화를 구현하면, 현재 구현에 종속되게 된다.
합당한 경우에만 기본 직렬화 형태를 사용해야한다.
그럼, 합당한 경우는 어떤게 있을까?
객체의 물리적표현과 논리적 표현이 모두 같은 경우가 있을 수 있다.
합당하지 않은 경우를 봐보자
연결리스트를 구현 했는데 직렬화를 하면서 노드에 연결된 모든 노드가 전부 직렬화가 되어버린다.
이렇게 객체의 물리적 표현과 논리적 표현의 차이가 생기면 문제점이 생긴다.
- 사이즈가 크고 시간이 많이 걸리며 메모리를 많이 사용한다.
합리적인 직렬화 형태를 봐보자
transient 필드는 직렬화에 포함시키지 않는다.
위 상태에서 writeObject 와 readObject 를 직렬화 시킬수있게 했다.
메소드를 봐보면 각각 defaultWriteObject를 호출 해준다.
defaultWriteObject 를 호출하면 transient 로 선언하지 않은 모든 필드가 직렬화 된다.
직렬화 명세에 이 과정이 무조건 있어야 나중에 transient 필드가 아닌 다른 필드가 추가 되도
이전 버전과 새로운 버전이 호환 된다고 한다.
동기화가 필요하면 메소드에 synchronized 를 붙여주자
readObject 메서드는 방어적으로 작성하라
인수의 유효성 검사와 매개변수를 방어적으로 복사하는 일이 필요하다.
인스턴스 수를 통제해야 한다면 readResolve보다는 열거 타입을 사용하라
싱글톤을 만들고 싶다면.. readResolve 사용 보다는 enum 을 사용하는게 좋다
이 코드는 static final 을 사용한 싱글톤 생성 코드인데,
여기에 serialize 를 붙이는 순간 싱글톤이 보장되지 않는다.
이걸 해결할때 자바 직렬화에서는 writeReplace 와 readResolve 를 제공해줘서
싱글톤을 유지시키는 방법이 있지만, 이걸 쓸때는
모든 필드값이 transient 여야 한다.
해결방법은 enum 을 이용해서 싱글톤을 만드는것이다.
직렬화된 인스턴스 대신 직렬화 프록시 사용을 검토하라
serialize 를 하는 순간 생성자 이외의 객체를 생성시키는 방법이 생기는 것이여서
보안 문제가 생길 수 있다.
이걸 직렬화 프록시를 사용하면 위험을 크게 줄일 수 있다.
중첩 클래스 직렬화 프록시를 만들어서 사용을 한다.
'Java > 이펙티브 자바' 카테고리의 다른 글
이펙티브 자바 - 11장 동시성 (0) | 2020.12.30 |
---|---|
이펙티브 자바 - 10장 예외 (0) | 2020.12.30 |
이펙티브 자바 - 9장 일반적인 프로그래밍 원칙 (0) | 2020.12.29 |
이펙티브 자바 - 8장 메서드 (0) | 2020.12.29 |
이펙티브 자바 - 7장 람다와 스트림 (0) | 2020.12.29 |