flawopen.com/XXE/Java XMLパーサーの安全性
Java XXE:DocumentBuilderFactoryは既定で安全?
JDKは一部の安全な処理制限を既定で有効にしますが、DOMとSAXの既定設定は外部リソースへのアクセスを遮断しません。アプリが明示的に制限しなければ、XMLがファイルやネットワークへのアクセスを引き起こす可能性があります。サードパーティのJAXP Providerで動作が変わることもあります。実際に使うパーサーを設定し、Javaのバージョンだけで安全性を判断しないでください。
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
DocumentBuilder builder =
factory.newDocumentBuilder();
Document document = builder.parse(untrustedXml);
// Java 9+:JAXP制限を明示的に有効化。
// 必須設定を使えない場合は安全に停止。
// パーサーは既定で外部アクセスを許す場合がある。
DocumentBuilderFactory factory =
DocumentBuilderFactory.newDefaultInstance();
// 実ファイルやサービスでテストしない。
factory.setFeature(
XMLConstants.FEATURE_SECURE_PROCESSING, true);
factory.setFeature(
"http://apache.org/xml/features/"
+ "disallow-doctype-decl", true);
factory.setAttribute(
XMLConstants.ACCESS_EXTERNAL_DTD, "");
factory.setXIncludeAware(false);
// サイズ制限は別途設定する。
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(untrustedXml);
DOCTYPE拒否が推奨されるDOM制御である理由
DOCTYPEを拒否できるパーサーでは、DTD由来の外部エンティティや宣言の処理を防げます。FEATURE_SECURE_PROCESSINGを明示的に有効にし、追加防御として外部DTDへのアクセスを制限します。JDKでFSPが既定で有効でも、外部接続が拒否されるとは限りません。必要な場合を除いてXIncludeを無効にし、必須設定をProviderが拒否したら部分的な強化のまま続行せず初期化を失敗させます。
DTDを受け入れる必要がある場合も外部アクセスを許可しないでください。外部一般/パラメーターエンティティ、外部DTDの読み込み、XIncludeを無効にし、ACCESS_EXTERNAL_DTDを空文字列にして処理制限を維持します。setExpandEntityReferences(false)はツリー表現を変える設定であり、外部リソースの遮断の代わりにはなりません。
各JAXPプロセッサを個別に強化する
同じ方針はXML処理全体に適用しますが、APIごとに設定が異なります。SAXParserFactory/XMLReader、StAXのXMLInputFactory、TransformerFactory、SchemaFactory、Validator、JAXBを確認してください。StAXはFEATURE_SECURE_PROCESSINGに対応しないため、専用プロパティでDTDと外部エンティティを無効にします。外部Schemaとstylesheetも制限し、OWASPのAPI別例と実際のProviderを確認してください。
1つのパーサー設定をJVM全体の保護とみなさないでください。JAXPのProvider選択で組み込み実装以外が使われたり、複合プロセッサが内部パーサーを作成したりします。本番と同じランタイム、Provider、コード経路をテストしてください。
よくある質問
既定で有効なだけでは遮断されません。Oracleの説明では既定のFSPは処理制限を適用しますが、APIで明示的に有効化するか外部アクセスプロパティを設定するまで外部接続は許可されます。ポリシーを明示し、Providerを確認してください。
JDKは制限を強化してきましたが、OracleのJAXPガイドは既定のFSPと外部アクセスの明示的な拒否を区別しています。サードパーティProviderも異なる場合があります。バージョンやclasspathの既定値に依存せず制御を設定してください。
信頼できるローカルカタログやresolverを優先します。DTDが必要なら外部プロトコルと外部エンティティ読み込みを遮断し、JAXP制限を維持してXIncludeを不要なら無効にします。DOCTYPE拒否より複雑なため、対象Providerと正当な文書でテストしてください。