설명
java.beans.XMLDecoder는 XML을 단순 데이터로 읽는 파서가 아니라 객체 생성과 메서드 호출을 복원하는 기능입니다. 신뢰할 수 없는 입력을 해석하면 공격자가 애플리케이션 권한으로 의도하지 않은 동작을 실행할 수 있습니다. 생성자를 호출하는 시점만이 아니라 문서 해석 중 실행되는 동작이 문제입니다.
잠재적 영향
- 코드 실행: 입력이 선택한 생성자나 메서드가 실행되어 프로세스 권한으로 작업할 수 있습니다.
- 민감 정보 접근: 애플리케이션이 접근할 수 있는 데이터와 시스템 자원이 노출될 수 있습니다.
- 데이터 조작과 서비스 장애: 객체 상태를 변경하거나 처리 자원을 소모할 수 있습니다.
해결 방법
- 신뢰할 수 없는 데이터에
XMLDecoder를 사용하지 마세요. 필요한 필드만 담은 JSON 등의 데이터 형식과 명시적인 모델로 프로토콜을 바꾸세요. - 사용자 지정
ClassLoader나 클래스 허용 목록만으로XMLDecoder를 안전하게 만들 수 있다고 가정하지 마세요. - 입력 필드·타입·크기를 검증하고 임의의 클래스 이름이나 다형성 타입 정보를 받아들이지 마세요. XML을 계속 사용한다면 객체 복원이 아닌 데이터 파서를 사용하고 DTD·외부 엔터티도 제한하세요.
예시
변경 전
java
import java.beans.XMLDecoder;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
public class InsecureXMLDecoder {
public static Object decode(String untrustedXml) {
try (XMLDecoder decoder = new XMLDecoder(new ByteArrayInputStream(
untrustedXml.getBytes(StandardCharsets.UTF_8)))) {
return decoder.readObject();
}
}
}
입력이 객체와 호출할 동작을 지정할 수 있습니다. 단순히 객체를 생성하는 것과 실제 프로세스를 시작하는 것은 구분해야 합니다.
변경 후
java
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public class MessageReader {
private static final ObjectMapper MAPPER = new ObjectMapper();
public static String readMessage(String json) throws IOException {
if (json == null || json.length() > 4096) {
throw new IllegalArgumentException("Invalid message size");
}
JsonNode data = MAPPER.readTree(json);
if (data == null || !data.isObject() || data.size() != 1
|| !data.path("message").isTextual()) {
throw new IllegalArgumentException("Expected a message string");
}
return data.get("message").textValue();
}
}
Jackson의 JSON 트리에서 message 문자열 하나만 읽습니다. 임의 타입 복원을 활성화하지 않으며, 기존 XML 객체 직렬화와 호환되는 대체 구현은 아니므로 호출자도 JSON 형식으로 바꿔야 합니다. 요청 본문 크기와 접근 권한은 호출 경계에서 별도로 제한하세요.