XML до сих пор используется в приложениях, веб-сервисах и старых корпоративных системах. Вместе с этим тянется и целый пласт проблем. Одна из самых известных уязвимостей связана с обработкой сущностей — XML External Entity (XXE). Несмотря на то что её описали много лет назад, она всё ещё регулярно встречается и нередко используется атакующими. Разберём, что это за уязвимость , какие есть её вариации и как от неё защититься.
Что такое XML и зачем нужны сущности
XML (eXtensible Markup Language) хранит данные в иерархической структуре. Чтобы не повторять одни и те же фрагменты текста, в XML можно объявлять сущности (entities). Сущность — это нечто вроде переменной: её описывают в DTD (Document Type Definition), а потом многократно используют.
Пример простой сущности:
<!DOCTYPE example [
<!ENTITY hello "Привет, мир!">
]>
<root>
<message>&hello;</message>
</root>
При обработке документа парсер подставит вместо &hello;
строку «Привет, мир!». Удобно, но именно эта механика становится лазейкой для атак.
Как работает XXE-атака
XXE строится на том, что XML-парсер доверяет входящему документу и разрешает внешние сущности. Внешняя сущность — это ссылка на внешний ресурс: локальный файл или сетевой адрес. Если приложение не отключает эту возможность, злоумышленник может заставить сервер загрузить данные откуда угодно.
Пример вредоносного XML:
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>
<data>&xxe;</data>
</root>
Парсер попытается подставить содержимое файла /etc/passwd
. Если результат выводится пользователю или куда-то логируется, злоумышленник получает доступ к конфиденциальной информации.
Типичные сценарии эксплуатации
- Чтение локальных файлов сервера.
- Обход аутентификации за счёт подмены данных.
- Запросы к внутренним сервисам (SSRF — Server-Side Request Forgery).
- Отказ в обслуживании через экспоненциальное разрастание сущностей.
Мутации XXE
В зависимости от настроек парсера XXE можно использовать по-разному. Атакующие комбинируют техники и добиваются разных результатов.
Billion Laughs Attack
DoS-атака на основе рекурсивного определения сущностей. Небольшой XML-файл превращается в гигантский поток данных, который перегружает память сервера.
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
...
]>
Эту технику называют ещё XML Bomb.
SSRF через XXE
Если разрешены сетевые обращения, XXE легко превращается в SSRF. Сервер начинает сам обращаться к внутренним сервисам или сторонним адресам. Это позволяет исследовать инфраструктуру и иногда обходить защиту.
Пример:
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "http://127.0.0.1:8080/admin">
]>
<root>&xxe;</root>
Blind XXE
Когда содержимое файла не попадает напрямую в ответ, используют Blind XXE. Данные кодируются в сетевые запросы, которые уходят на сервер атакующего. Так он собирает утечки из логов.
Как обнаружить XXE
Проверять систему можно вручную или с помощью инструментов:
- Burp Suite — подмена XML-запросов и анализ ответов.
- OWASP ZAP — бесплатный сканер уязвимостей.
- RequestBin — перехват SSRF-запросов.
На уязвимость указывают:
- Задержки в ответах при изменении XML.
- Ошибки парсера.
- Неожиданные сетевые запросы от приложения.
Как защититься от XXE
Главное — отключить поддержку внешних сущностей в парсере. Но есть и дополнительные меры.
Базовые шаги
- Запретите
DOCTYPE
и внешние сущности. - Используйте библиотеки, которые по умолчанию блокируют XXE.
- Фильтруйте входящие данные.
- Ограничьте доступ приложения к файловой системе и внутренним сетям.
Примеры в коде
Java:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
Python (lxml):
from lxml import etree
parser = etree.XMLParser(resolve_entities=False)
XXE сегодня
XXE всё ещё фигурирует в списке OWASP Top 10 . Она встречается в отчётах по кибербезопасности именно потому, что разработчики часто используют небезопасные настройки по умолчанию или старые парсеры.
XML до сих пор применяется в банковских сервисах, SOAP-API и интеграциях. Там, где JSON занял лидирующие позиции, XXE встречается реже, но полностью не исчезла.
Заключение
XXE — пример того, как полезная функция превращается в угрозу. Проверка систем на эту уязвимость и правильные настройки парсера способны предотвратить серьёзные инциденты. Если вы работаете с XML, стоит убедиться, что внешние сущности отключены. Это простое действие может закрыть большую дыру в безопасности.