Swift FoundationのXML外部エンティティ(XXE)

Swift FoundationのXML外部エンティティ(XXE)

説明

XML外部エンティティ(XXE)の脆弱性は、信頼できないXMLのDTDやエンティティ宣言を安全でない方法で処理すると発生します。攻撃者にローカルファイルやネットワークリソースを読み込まれたり、エンティティの展開を繰り返してリソースを使い果たされたりするおそれがあります。

Foundationの XMLParser.shouldResolveExternalEntities の既定値は false で、新しい externalEntityResolvingPolicy の既定値は .never です。これらの保護された既定値を維持してください。Appleは、shouldResolveExternalEntities を有効にすると、外部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 は parse() を呼ぶ前に適用してください。

参考資料