Разберите уязвимость XXE (XML External Entity) на примере Java-парсера: как атакующий может получить доступ к файлам сервера и провести SSRF, и какие настройки/библиотеки предотвращают эту проблему
Что такое XXE (коротко) - XXE — уязвимость, когда XML-парсер обрабатывает внешние сущности (external entities / DTD). Злоумышленник подставляет в XML DOCTYPE с внешней сущностью, парсер загружает содержимое по указанному URI и вставляет его в документ — это даёт чтение файлов, SSRF и возможность OOB-утечки. Пример злонамеренного XML - для чтения файла: <!DOCTYPE root [ ]>&xxe;
- для SSRF (или OOB): <!DOCTYPE root [ ]>&xxe;
Как атакующий получает данные - Парсер при обработке DOCTYPE запрашивает указанный URI. Если приложение возвращает или логирует содержимое элементов XML (например textContent), то файл/ответ от внутреннего сервера попадёт к атакующему. Даже при небинарном выводе возможна OOB-утечка через HTTP/DNS-запросы на контролируемый сервер. Уязвимый Java-пример (DocumentBuilder) - уязвимый код: DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(new InputSource(new StringReader(xml))); - по умолчанию многие реализации разрешают DTD и внешние сущности — приведённый код восприимчив к XXE. Как защититься (рекомендуемые настройки) 1) Отключить DTD/внешние сущности полностью (рекомендуется): DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); // запретить DOCTYPE dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); dbf.setXIncludeAware(false); dbf.setExpandEntityReferences(false); dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); 2) Альтернативный/дополнительный способ — явно запретить доступ к внешним ресурсам: dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); // запретить внешние DTD dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); // при необходимости 3) Для SAXParserFactory аналогичные флаги: SAXParserFactory spf = SAXParserFactory.newInstance(); spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); spf.setFeature("http://xml.org/sax/features/external-general-entities", false); spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); 4) Для StAX (XMLInputFactory): XMLInputFactory xif = XMLInputFactory.newInstance(); xif.setProperty(XMLInputFactory.SUPPORT_DTD, false); xif.setProperty("javax.xml.stream.isSupportingExternalEntities", false); 5) Для TransformerFactory / XSLT: TransformerFactory tf = TransformerFactory.newInstance(); tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); 6) Для JAXB — отключать DTD через XMLInputFactory/Unmarshaller источника (т.е. парсить через защищённый XMLInputFactory) или применять те же флаги к используемому парсеру. Дополнительные меры защиты - Если возможно, полностью запрещайте DOCTYPE для входящего XML. - Применяйте принцип наименьших привилегий: запускать процесс без прав чтения чувствительных файлов. - Сеть: запрещайте исходящие HTTP/DNS-запросы сервером или используйте egress-фильтрацию, чтобы предотвратить SSRF/OOB-утечки. - Обновляйте библиотеки/JDK и следуйте OWASP XXE Prevention Cheat Sheet. - По возможности используйте безопасные альтернативы (JSON-библиотеки) для данных из ненадёжных источников. Коротко: не разрешайте DTD/внешние сущности по умолчанию и применяйте свойства/фичи парсера, приведённые выше; комбинируйте с сетевой политикой и правами процесса.
- XXE — уязвимость, когда XML-парсер обрабатывает внешние сущности (external entities / DTD). Злоумышленник подставляет в XML DOCTYPE с внешней сущностью, парсер загружает содержимое по указанному URI и вставляет его в документ — это даёт чтение файлов, SSRF и возможность OOB-утечки.
Пример злонамеренного XML
- для чтения файла:
<!DOCTYPE root [ ]>&xxe; - для SSRF (или OOB):
<!DOCTYPE root [ ]>&xxe;
Как атакующий получает данные
- Парсер при обработке DOCTYPE запрашивает указанный URI. Если приложение возвращает или логирует содержимое элементов XML (например textContent), то файл/ответ от внутреннего сервера попадёт к атакующему. Даже при небинарном выводе возможна OOB-утечка через HTTP/DNS-запросы на контролируемый сервер.
Уязвимый Java-пример (DocumentBuilder)
- уязвимый код:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new InputSource(new StringReader(xml)));
- по умолчанию многие реализации разрешают DTD и внешние сущности — приведённый код восприимчив к XXE.
Как защититься (рекомендуемые настройки)
1) Отключить DTD/внешние сущности полностью (рекомендуется):
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); // запретить DOCTYPE
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
2) Альтернативный/дополнительный способ — явно запретить доступ к внешним ресурсам:
dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); // запретить внешние DTD
dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); // при необходимости
3) Для SAXParserFactory аналогичные флаги:
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
spf.setFeature("http://xml.org/sax/features/external-general-entities", false);
spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
4) Для StAX (XMLInputFactory):
XMLInputFactory xif = XMLInputFactory.newInstance();
xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
xif.setProperty("javax.xml.stream.isSupportingExternalEntities", false);
5) Для TransformerFactory / XSLT:
TransformerFactory tf = TransformerFactory.newInstance();
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
6) Для JAXB — отключать DTD через XMLInputFactory/Unmarshaller источника (т.е. парсить через защищённый XMLInputFactory) или применять те же флаги к используемому парсеру.
Дополнительные меры защиты
- Если возможно, полностью запрещайте DOCTYPE для входящего XML.
- Применяйте принцип наименьших привилегий: запускать процесс без прав чтения чувствительных файлов.
- Сеть: запрещайте исходящие HTTP/DNS-запросы сервером или используйте egress-фильтрацию, чтобы предотвратить SSRF/OOB-утечки.
- Обновляйте библиотеки/JDK и следуйте OWASP XXE Prevention Cheat Sheet.
- По возможности используйте безопасные альтернативы (JSON-библиотеки) для данных из ненадёжных источников.
Коротко: не разрешайте DTD/внешние сущности по умолчанию и применяйте свойства/фичи парсера, приведённые выше; комбинируйте с сетевой политикой и правами процесса.