오늘날 소프트웨어 개발 환경에서는 데이터를 저장, 전송, 처리하는 과정이 필수적입니다.
우리는 웹 애플리케이션, 데이터베이스, 네트워크 프로토콜, 파일 시스템 등에서 데이터를 효율적으로 다루기 위해 다양한 기술을 사용합니다.
이 과정에서 "객체(Object) 데이터를 효율적으로 저장하고, 필요할 때 다시 불러올 수 있다면 어떨까요?"
또한, "네트워크를 통해 객체(Object)를 전송할 때 이를 안전하게 주고받을 수 있는 방법은 무엇일까요?"
이 문제를 해결하는 것이 바로 직렬화(Serialization)와 역직렬화(Deserialization) 입니다.
하지만, 여기서 주의해야 할 중요한 점이 있습니다.
잘못된 역직렬화는 보안 취약점을 발생시켜 공격자가 이를 악용할 수도 있습니다.
실제로 많은 보안 사고가 역직렬화 취약점을 통해 발생하며, 보안에 대한 인식이 부족한 개발자들에게 치명적인 결과를 초래할 수 있습니다.
그렇다면,
✅ 직렬화와 역직렬화는 정확히 무엇일까요?
✅ 어떻게 사용하며, 어떤 문제점이 존재할까요?
✅ 보안 취약점을 피하고 안전하게 데이터를 관리하는 방법은 무엇일까요?
이번 포스팅에서는 직렬화와 역직렬화의 개념, 실무 활용, 보안 취약점 및 안전한 코드 작성 방법을 구체적으로 설명하겠습니다. 개발자들이 보다 안전한 시스템을 구축하고, 직렬화된 데이터를 효과적으로 활용할 수 있도록 깊이 있는 내용을 준비했으니 끝까지 읽어주세요! 🚀
1. 직렬화와 역직렬화란?
1.1 직렬화(Serialization) : 객체 데이터를 바이트 스트림(byte stream)으로 변환하여 저장하거나 전송할 수 있도록 하는 과정.
1.2 역직렬화(Deserialization) : 직렬화된 바이트 스트림을 다시 객체로 복원하는 과정. 잘못된 역직렬화 처리 시 보안 취약점 발생 가능.
2. 직렬화 및 역직렬화 코드 예제
2.1 Java에서 직렬화 및 역직렬화 예제
import java.io.*;
class Person implements Serializable {
private static final long serialVersionUID = 1L;
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class SerializationExample {
public static void main(String[] args) {
Person person = new Person("Alice", 25);
// 직렬화
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser"))) {
oos.writeObject(person);
System.out.println("직렬화 완료!");
} catch (IOException e) {
e.printStackTrace();
}
// 역직렬화
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.ser"))) {
Person deserializedPerson = (Person) ois.readObject();
System.out.println("역직렬화 완료! 이름: " + deserializedPerson.name);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
- Serializable 인터페이스를 구현하면 해당 객체를 직렬화할 수 있음
- ObjectOutputStream을 사용하여 객체를 파일(.ser)로 저장
- ObjectInputStream을 사용하여 저장된 데이터를 객체로 복원(역직렬화)
2.2 Python에서 직렬화 및 역직렬화 예제
import pickle
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# 직렬화
person = Person("Bob", 30)
with open("person.pkl", "wb") as f:
pickle.dump(person, f)
print("직렬화 완료!")
# 역직렬화
with open("person.pkl", "rb") as f:
loaded_person = pickle.load(f)
print(f"역직렬화 완료! 이름: {loaded_person.name}, 나이: {loaded_person.age}")
✅ 설명
- pickle 모듈을 사용하여 객체를 파일로 저장(직렬화)
- pickle.load()를 사용하여 다시 객체로 변환(역직렬화)
3. 직렬화 및 역직렬화 보안 취약점 및 해결 방법
3.1 보안 취약점 (Insecure Deserialization)
- 역직렬화 시 공격자가 악의적인 객체를 삽입하여 원격 코드 실행(RCE, Remote Code Execution)이 가능
- 공격자는 조작된 바이트 스트림을 서버로 전송하여 임의의 코드 실행, 시스템 접근 권한 탈취, 데이터 변조 등의 공격을 수행
3.2 보안 취약점 예제 (Java 역직렬화 취약점 - 공격 코드 포함)
import java.io.*;
class Exploit implements Serializable {
private static final long serialVersionUID = 1L;
static {
try {
Runtime.getRuntime().exec("calc.exe"); // Windows 계산기 실행 (공격 가능)
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class InsecureDeserialization {
public static void main(String[] args) {
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("exploit.ser"))) {
oos.writeObject(new Exploit());
System.out.println("악성 객체 직렬화 완료!");
} catch (IOException e) {
e.printStackTrace();
}
// 역직렬화 실행 (취약 코드 실행됨)
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("exploit.ser"))) {
ois.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
✅ 문제점:
- 공격자가 calc.exe 대신 시스템 명령어를 실행하는 코드를 삽입하면 서버 해킹 가능
- Java의 역직렬화 취약점은 Log4j, Apache Commons-Collections 등의 라이브러리에서도 발생
3.3 안전한 직렬화 및 역직렬화 방법
1️⃣ 신뢰할 수 없는 데이터 역직렬화 방지
- JSON, XML과 같은 안전한 데이터 포맷 사용
- readObject() 사용 시 허용된 클래스만 역직렬화
2️⃣ 역직렬화 시 객체 필터링 적용 (Java 9 이상 지원)
import java.io.*;
public class SafeDeserialization {
public static void main(String[] args) {
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("safe.ser"))) {
Object obj = ois.readObject();
if (obj instanceof Person) {
Person person = (Person) obj;
System.out.println("안전한 역직렬화 완료: " + person.name);
} else {
throw new SecurityException("허용되지 않은 객체 역직렬화 차단!");
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
3️⃣ Python에서 안전한 직렬화 방법
- pickle 대신 json 모듈 사용 (pickle은 임의 코드 실행 가능)
import json
data = {"name": "Alice", "age": 25}
# 안전한 직렬화
json_data = json.dumps(data)
print(f"직렬화된 데이터: {json_data}")
# 안전한 역직렬화
loaded_data = json.loads(json_data)
print(f"역직렬화된 데이터: {loaded_data}")
4. 🎯 결론
- 직렬화(Serialization): 객체 데이터를 바이트 스트림으로 변환하여 저장 및 전송 가능
- 역직렬화(Deserialization): 바이트 스트림을 객체로 변환하는 과정
- 보안 취약점: 잘못된 역직렬화는 해커에게 공격 기회를 제공 (원격 코드 실행, 데이터 변조)
- 안전한 사용법: 허용된 클래스만 역직렬화, JSON/XML 사용, 신뢰할 수 없는 데이터 차단
✅ 직렬화와 역직렬화는 강력한 기능이지만, 보안 취약점을 반드시 고려해야 합니다! 🚀
'Security보안' 카테고리의 다른 글
[IT보안용어]인증(Authentication)과 인가(Authorization)의 개념부터 실전 코드까지 (1) | 2025.03.24 |
---|---|
랜섬웨어 감염 시 대응법: 몸값 지불? 복구? 최선의 선택은? (1) | 2025.03.19 |
피싱, 스미싱, 파밍의 유래와 차이점, 그리고 위험성 🚨 (2) | 2025.03.12 |
내 개인정보는 해킹으로부터 지금 안전한가? 🔐 (0) | 2025.03.12 |
[IT보안용어]화이트 해커(White Hat)와 블랙 해커(Black Hat)의 유래와 차이점 (0) | 2025.03.07 |