📦 안전하지 않은 역직렬화 시뮬레이터 KISA A-5 · 신뢰할 수 없는 데이터의 역직렬화
엔드포인트가 공격자가 조작한 바이트를 역직렬화합니다. 네이티브 역직렬화기(Java ObjectInputStream, PHP unserialize, Python pickle)는 임의 클래스를 생성하고 로드 시 '매직' 메서드를 호출할 수 있습니다 — 명령 실행(RCE)으로 끝나는 가젯 체인이 됩니다.
① 취약한 엔드포인트: POST /restore (네이티브 역직렬화) VULNERABLE
서버는 본문을 base64 디코딩해 네이티브 역직렬화기에 그대로 넘깁니다. 바이트가 선언한 타입을 무엇이든 복원하며 생성자/
readObject/__wakeup/__reduce__ 훅을 실행합니다 — 따라서 조작된 객체는 앱 로직이 보기도 전에 '로드' 중에 코드를 실행합니다.
② 안전한 엔드포인트: JSON + 스키마 + 클래스 허용목록 SECURE
수정본은 네이티브 역직렬화를 절대 하지 않습니다. JSON(데이터만, 코드/타입 없음)을 파싱하고 엄격한 스키마로 검증한 뒤, 예상되는 소수의 클래스 허용목록으로만 매핑합니다. 가젯 페이로드는 파싱 또는 스키마/허용목록 검사에서 실패합니다 — 객체 생성 훅이 전혀 발화하지 않습니다.
③ 취약 vs 안전 코드
VULNERABLE — Java / Python
// Java: 임의 객체 복원 + readObject 가젯
ObjectInputStream ois =
new ObjectInputStream(req.getInputStream());
Object o = ois.readObject(); // ← 여기서 가젯 실행
# Python: pickle 은 __reduce__ 로 임의 호출
import pickle
data = base64.b64decode(body)
obj = pickle.loads(data) # ← os.system(...) 실행
SECURE — JSON + schema + allow-list
// 데이터만 파싱 (코드/타입 복원 없음)
JsonNode n = mapper.readTree(body);
validateSchema(n, ORDER_SCHEMA); // 엄격 검증
if(!ALLOWED.contains(n.get("type").asText()))
throw new SecurityException("type not allowed");
Order o = mapper.treeToValue(n, Order.class);
# Python: json + 명시적 매핑
d = json.loads(body) # 데이터만
assert set(d) <= {"id","qty"} # 허용 키만
order = Order(id=int(d["id"]), qty=int(d["qty"]))
방어 핵심: 신뢰할 수 없는 입력을 네이티브 역직렬화하지 말 것 · 데이터 전용 포맷(JSON)으로 받아 객체를 명시적으로 생성 · 엄격한 스키마와 클래스/필드 허용목록 강제 · 왕복이 필요한 페이로드는 서명/암호화 · 불가피하면 look-ahead/ObjectInputFilter 허용목록 + 최소 권한 실행.
⚠️ 교육용 시뮬레이션입니다. 직렬화 블롭·가젯 체인·'실행된' 명령은 모두 mock JS 표현이며 실제 역직렬화기나 명령 실행은 일어나지 않습니다.