🧩 XML 삽입 시뮬레이터 KISA #9 · XML 삽입

요청 필드가 검증 없이 서버가 파싱하는 XML 문서(주문/SOAP 메시지)에 그대로 연결됩니다. 이스케이프되지 않은 입력은 추가 XML 태그를 주입해 role·price 같은 형제 필드를 덮어쓸 수 있습니다.

① 취약: 문자열 연결로 만든 XML 주문 VULNERABLE

서버는 주문 XML을 연결로 만듭니다: <user><name>{name}</name><role>user</role></user>. name이 이스케이프되지 않으므로 주입된 </name>...</role>가 요소를 일찍 닫고 새 태그를 위조합니다. 대부분의 XML 파서는 중복 요소 중 마지막 값을 채택하므로, 주입된 role이 실제 값을 덮어씁니다.

② 안전: XML 이스케이프 + DOM 빌더 SECURE

수정본은 삽입 전에 XML 메타문자 5종(& < > " ')을 이스케이프하거나, 더 나아가 DOM/파라미터화 빌더로 트리를 만들어 텍스트가 항상 텍스트 노드로만 남게 합니다. 스키마 검증으로 범위 밖 값은 거부합니다.

③ 취약 vs 안전 코드 (Java / JAXP)

VULNERABLE
// Java — 문자열 연결로 XML 조립 (위험)
String xml =
  "<order><user><name>" + name +
  "</name><role>user</role></user>" +
  "<qty>" + qty + "</qty></order>";

Document doc = DocumentBuilderFactory.newInstance()
   .newDocumentBuilder()
   .parse(new InputSource(new StringReader(xml)));
// name = "x</name><role>admin</role><name>y"
// → role 요소가 추가 주입되어 admin 으로 승격
SECURE
// Java — DOM 빌더 + 이스케이프 + 스키마 검증
Document doc = DocumentBuilderFactory.newInstance()
                 .newDocumentBuilder().newDocument();
Element user = doc.createElement("user");
Element nm  = doc.createElement("name");
nm.appendChild(doc.createTextNode(name)); // 항상 텍스트
Element role = doc.createElement("role");
role.appendChild(doc.createTextNode("user")); // 서버 고정
user.appendChild(nm); user.appendChild(role);

int q = Integer.parseInt(qty);            // 타입 검증
if (q < 1 || q > 999) throw new BadRequest();
// 스키마(XSD) 검증으로 구조까지 강제
방어 핵심: 신뢰할 수 없는 텍스트를 XML 마크업에 연결 금지 · & < > " ' 이스케이프 또는 DOM 텍스트 노드 사용 · XSD 스키마 검증 · role·price 같은 보안 필드는 클라이언트가 아니라 서버에서 고정.
XXE와 구분: XXE는 외부/DTD 엔티티로 파일을 읽는 공격이고, XML 삽입은 이스케이프되지 않은 데이터로 문서 구조를 위조하는 공격입니다.
⚠️ 교육용 시뮬레이션입니다. 모든 XML은 페이지 내부 mock 대상에서만 생성·파싱되며 실제 시스템에 접근하지 않습니다.