자바 직렬화란?
자바 직렬화(Java Serialization)는 자바 객체를 바이트 스트림으로 변환하여 저장하거나 네트워크로 전송한 후 다시 복원할 수 있도록 하는 기술이다.
주로 외부 파일이나 네트워크를 통해 객체 데이터를 주고받을 때 사용된다.
JSON은 웹(Web) 뿐만 아니라 게임 쪽에서도 설정 파일로 쓰이거나 데이터를 교환할 때 범용적으로 사용된다.
그리고 직렬화는 오로지 자바 프로그램에서만 사용이 가능하지만, JSON 형태로 객체 데이터를 저장해 두면 파이썬, 자바스크립트에서도 범용적으로 사용이 가능하다.
문득 이런 생각이 들 것이다. CSV, JSON 이라는 훌륭한 데이터 포맷이 있는데 굳이 자바 직렬화가 필요할까?
자바 직렬화를 왜 사용할까?
1. 자바 환경에서만 객체를 저장하거나 전송해야 할 때
자바 직렬화는 자바 애플리케이션 간 데이터(객체)를 전송에 최적화되어 있다.
예를 들어 자바 RMI(Remote Method Invocation)와 같은 분산 시스템에서 객체를 네트워크로 전송할 때 사용된다.
자바 RMI(Remote Method Invocation)란?
분산 시스템에서 원격 객체의 메서드를 호출할 수 있도록 해주는 자바의 기술이다.
즉, 네트워크를 통해 다른 JVM에 있는 객체의 메서드를 마치 로컬 메서드처럼 호출할 수 있게 해주는 것이다.
2. 자바 객체를 영구적으로 저장해야 할 때
객체를 파일로 저장하거나 데이터베이스에 기록할 때 자바 직렬화를 사용할 수 있다.
예를 들어 서블릿 세션 데이터를 저장하거나 복원할 때도 자바 직렬화가 활용된다.
하지만 외부(DB, 캐시 서버, NoSQL 서버 등)에 장기간 저장될 정보는 자바 직렬화 사용을 지양해야 한다.
그 이유는 아래에서 설명하겠다.
자바 직렬화는 어디에 사용되나?
1. 서블릿 세션 데이터 저장
서블릿 기반의 WAS(톰캣, 웹로직 등)들은 대부분 세션의 자바 직렬화를 지원하고 있다.
물론 단순히 세션을 서블릿 메모리 위에서 운용한다면 직렬화를 필요로 하지 않지만, 파일로 저장하거나 세션 클러스터링, DB를 저장하는 옵션 등을 선택하게 되면 세션 자체가 직렬화가 되어 저장되어 전달된다.
(그래서 세션에 필요한 객체는 java.io.Serializable
인터페이스를 구현(implements
) 해두는 것을 추천한다.)
2. 캐시 (Cache)
자바 시스템에서 퍼포먼스를 위해 캐시 라이브러리(ex. redis)를 시스템을 많이 이용하게 된다.
예를 들면 DB 조회 결과를 메모리(Ehcache, Redis 등)에 저장하고, 동일한 요청이 오면 DB를 다시 요청하는 것이 아니라 저장된 객체를 찾아서 응답하게 할 수 있다.
이처럼 캐시를 이용하면 DB에 대한 리소스를 절약할 수 있기 때문에 많은 시스템에서 자주 활용된다.
3. 자바 RMI
최근에는 많이 사용되지 않지만 자바 직렬화를 설명할 때는 빠지지 않고 이야기되는 기술이다.
위에서 간단하게 설명했지만 자바 RMI는 원격 시스템 간의 메시지 교환을 위해서 사용하는 자바에서 지원하는 기술이다.
보통은 원격의 시스템과의 통신을 위해서 IP와 포트를 이용해서 소켓통신을 해야 하지만 RMI는 그 부분을 추상화하여 원격에 있는 시스템의 메서드를 로컬 시스템의 메서드인 것처럼 호출할 수 있다.
원격의 시스템의 메서드를 호출 시에 전달하는 메시지(보통 객체)를 자동으로 직렬화시켜 사용된다.
그리고 전달받은 원격 시스템에서는 메시지를 역직렬화를 통해 변환하여 사용한다.
자바 직렬화의 장점
1. 자바 환경에 최적화
자바 객체의 구조와 데이터를 효율적으로 처리할 수 있도록 설계되었으며, 레퍼런스 타입과 복잡한 객체 구조를 지원한다.
2. 구현이 간단하다.
Serializable
인터페이스를 구현하기만 하면 직렬화 및 역직렬화를 쉽게 사용할 수 있다. 추가적인 설정 없이도 기능을 제공한다.
자바 직렬화의 문제점
자바 직렬화는 간단하고 강력한 기능을 제공하지만, 다음과 같은 문제점이 있다.
1. 직렬화는 용량이 크다
직렬화된 데이터는 객체의 값뿐만 아니라 타입 정보와 클래스 메타데이터까지 포함하므로, JSON이나 XML과 같은 포맷에 비해 용량이 크다. 최소 2배~최대 10배까지 차이가 난다.
따라서 DB, Cache 등에 외부에 저장할때, 장기간 동안 저장하는 정보는 직렬화를 지양해야 된다.
2. 역직렬화는 위험하다
역직렬화는 보안 문제를 유발할 수 있다. 공격자가 조작된 바이트 스트림을 전달하여 객체의 상태를 변조하거나, 악성 코드 실행을 유도할 가능성이 있다.
역직렬화 과정에서 호출되어 잠재적으로 위험한 동작을 수행하는 메서드를 가젯(gadget)이라고 부르는데, 바이트 스트림을 역직렬화하는 ObjectInputStream의 readObject() 메서드를 호출하게 되면 객체 그래프가 역직렬화되어 classpath 안의 모든 타입의 객체를 만들어 내게 되는데, 해당 타입 객체 안의 모든 코드를 수행할 수 있게 되므로 나의 프로그램 코드 전체가 공격 범위에 들어가게 된다.
또는 객체를 직렬화하여 외부로 전송하는 과정에서 중간에 누가 가로채 파일 바이트 내용을 조작하여, 송신자가 역직렬화하는 과정에서 인스턴스에 위험한 값을 대입시켜 불변을 깨는 식으로의 공격도 가능하다. 왜냐하면 역직렬화는 생성자 없이 인스턴스화가 가능하기 때문에 보이지 않는 생성자 라고도 불린다.
따라서 신뢰할 수 없는 데이터는 절대 역직렬화하면 안 되며, 직렬화의 잠재적인 위험성을 회피하는 가장 좋은 방법은 아무것도 역직렬화하지 않는 것이 좋다.
3. 릴리즈 후에 수정이 어렵다
클래스가 Serializable
을 구현하게 되면 직렬화된 바이트 스트림 인코딩도 하나의 공개 API가 되는 것이다.
그래서 직렬화를 구현한 클래스가 널리 퍼지면 그 직렬화 형태도 영원히 지원해야 한다. 클래스의 내부 구현을 수정한다면 원래의 직렬화 형태와 달라지게 되기 때문이다.
그래서 직렬화된 객체를 사용하는 동안 클래스 구조를 변경하면, 기존 데이터와의 호환성 문제가 발생할 수 있다. 유지보수 헬게이트가 열리는 것이다.
4. 클래스 캡슐화가 깨진다
직렬화할 클래스에 private 멤버가 있어도 직렬화를 하게 되면 그대로 외부로 노출되게 된다. 외부에 노출하지 않으려면 직렬화 제외 필드(transient
)를 설정해야 한다.
자바 직렬화와 JSON의 비교
항목 | 자바 직렬화 | JSON |
---|---|---|
언어 의존성 | 자바에서만 사용 가능 | 언어에 독립적 (Python, JavaScript 등과 호환 가능) |
파일 크기 | 메타데이터 포함으로 인해 크기가 큼 | 상대적으로 작음 |
구현 난이도 | Serializable 인터페이스로 간단히 구현 가능 |
JSON 라이브러리를 사용하여 구현 |
범용성 | 자바 애플리케이션 간 데이터 교환에 특화 | 데이터 교환, 설정 파일 등 다양한 용도로 사용 가능 |
보안 | 역직렬화 과정에서 보안 문제가 발생할 수 있음 | 보안성이 더 높음 |
참고
자바 직렬화, 그것이 알고싶다. 훑어보기편
자바 직렬화, 그것이 알고싶다. 실무편
자바 직렬화(Serializable) - 완벽 마스터하기
'💻 Dev > Java' 카테고리의 다른 글
JDBC 드라이버 로딩으로 알아보는 Class.forName (0) | 2025.01.03 |
---|---|
스레드 로컬(Thread Local)이란? (0) | 2024.12.29 |
자바는 왜 Lambda&Stream을 도입했을까? feat.함수형 프로그래밍 (0) | 2024.12.26 |
리플렉션(Reflection)으로 DI 구현해보기 +단점 (0) | 2024.12.22 |
Stack은 왜 상속의 실패 사례일까? (0) | 2024.12.12 |
System.out.println을 실무에서 사용하면 안되는 이유 (1) | 2024.12.05 |