説明
XML外部エンティティ(XXE)の脆弱性は、信頼できないXMLのDTDやエンティティ宣言を安全でない方法で処理すると発生します。攻撃者にローカルファイルやネットワークリソースを読み込まれたり、エンティティの展開を繰り返してリソースを使い果たされたりするおそれがあります。
Foundationの XMLParser.shouldResolveExternalEntities の既定値は false で、新しい externalEntityResolvingPolicy の既定値は .never です。これらの保護された既定値を維持してください。Appleは、shouldResolveExternalEntities を有効にすると、外部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はparse()を呼ぶ前に適用してください。