설명
XML 외부 엔티티(XML External Entity, XXE) 취약점은 신뢰할 수 없는 XML의 DTD 또는 엔티티 선언을 안전하지 않게 처리할 때 발생합니다. 공격자는 파서가 로컬 파일이나 네트워크 리소스를 읽도록 유도하거나, 반복적인 엔티티 확장으로 리소스를 고갈시킬 수 있습니다.
Foundation의 XMLParser.shouldResolveExternalEntities 기본값은 false이고, 최신 외부 엔티티 해석 정책인 externalEntityResolvingPolicy의 기본값은 .never입니다. 이 안전한 기본값을 유지하면 별도의 활성화가 필요하지 않습니다. Apple은 shouldResolveExternalEntities를 true로 설정하면 외부 DTD를 불러오는 과정에서 네트워크 또는 디스크 I/O가 발생할 수 있다고 경고합니다. 실제 영향은 적용된 해석 정책과 XMLParserDelegate 구현에 따라 달라집니다.
잠재적 영향
- 로컬 파일 또는 앱 데이터 노출
- 내부 서비스에 대한 서버 측 요청 위조(SSRF) 또는 포트 탐색
- 반복적 엔티티 확장과 대용량 DTD로 인한 메모리·CPU 고갈
- 응답에 결과가 포함되지 않아도 가능한 대역 외 데이터 유출
해결 방법
- 신뢰할 수 없는 XML에서는
shouldResolveExternalEntities를 설정하지 않은 기본 상태로 두거나,parse()전에false로 설정합니다. - 최신 Foundation 대상에서는
externalEntityResolvingPolicy도.never로 유지합니다. 이후 코드가 두 설정을 다시 활성화하지 않는지 확인합니다. .noNetwork는 네트워크 로드만 막을 뿐 외부 엔티티 해석 자체를 끄지 않으므로 일반적인 해결책으로 사용하지 않습니다.- 외부 엔티티가 반드시 필요하다면 해당 워크플로를 신뢰할 수 없는 XML 처리와 분리하고, 정확히 사전 승인된 엔티티 URL만 허용합니다.
- 입력 크기와 처리 시간에 제한을 두되, 이를 엔티티 해석 비활성화의 대체 수단으로 간주하지 않습니다.
예시
변경 전
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는 파싱 전에 적용되어야 합니다.