Swift Foundation XML 외부 엔티티(XXE)

Swift Foundation XML 외부 엔티티(XXE)

설명

XML 외부 엔티티(XML External Entity, XXE) 취약점은 신뢰할 수 없는 XML의 DTD 또는 엔티티 선언을 안전하지 않게 처리할 때 발생합니다. 공격자는 파서가 로컬 파일이나 네트워크 리소스를 읽도록 유도하거나, 반복적인 엔티티 확장으로 리소스를 고갈시킬 수 있습니다.

Foundation의 XMLParser.shouldResolveExternalEntities 기본값은 false이고, 최신 외부 엔티티 해석 정책인 externalEntityResolvingPolicy의 기본값은 .never입니다. 이 안전한 기본값을 유지하면 별도의 활성화가 필요하지 않습니다. Apple은 shouldResolveExternalEntities를 true로 설정하면 외부 DTD를 불러오는 과정에서 네트워크 또는 디스크 I/O가 발생할 수 있다고 경고합니다. 실제 영향은 적용된 해석 정책과 XMLParserDelegate 구현에 따라 달라집니다.

잠재적 영향

  • 로컬 파일 또는 앱 데이터 노출
  • 내부 서비스에 대한 서버 측 요청 위조(SSRF) 또는 포트 탐색
  • 반복적 엔티티 확장과 대용량 DTD로 인한 메모리·CPU 고갈
  • 응답에 결과가 포함되지 않아도 가능한 대역 외 데이터 유출

해결 방법

  1. 신뢰할 수 없는 XML에서는 shouldResolveExternalEntities를 설정하지 않은 기본 상태로 두거나, parse() 전에 false로 설정합니다.
  2. 최신 Foundation 대상에서는 externalEntityResolvingPolicy도 .never로 유지합니다. 이후 코드가 두 설정을 다시 활성화하지 않는지 확인합니다.
  3. .noNetwork는 네트워크 로드만 막을 뿐 외부 엔티티 해석 자체를 끄지 않으므로 일반적인 해결책으로 사용하지 않습니다.
  4. 외부 엔티티가 반드시 필요하다면 해당 워크플로를 신뢰할 수 없는 XML 처리와 분리하고, 정확히 사전 승인된 엔티티 URL만 허용합니다.
  5. 입력 크기와 처리 시간에 제한을 두되, 이를 엔티티 해석 비활성화의 대체 수단으로 간주하지 않습니다.

예시

변경 전

swift
import Foundation

func parseRemoteXML() throws {
    let remoteData = try Data(
        contentsOf: URL(string: "https://example.com/input.xml")!
    )
    let parser = Foundation.XMLParser(data: remoteData)
    parser.externalEntityResolvingPolicy = .always
    parser.shouldResolveExternalEntities = true
    _ = parser.parse()
}

변경 후

swift
import Foundation

func parseRemoteXML() throws {
    let remoteData = try Data(
        contentsOf: URL(string: "https://example.com/input.xml")!
    )
    let parser = Foundation.XMLParser(data: remoteData)
    parser.externalEntityResolvingPolicy = .never
    parser.shouldResolveExternalEntities = false
    _ = parser.parse()
}

설명:

  • 변경 전: 원격 XML을 받은 파서에서 외부 엔티티 로드를 허용한 뒤 파싱합니다.
  • 변경 후: 최신 정책과 불리언 플래그를 모두 안전한 값으로 고정한 뒤 파싱합니다. false와 .never는 파싱 전에 적용되어야 합니다.

참조