# V5614. OWASP. Potential XXE vulnerability. Insecure XML parser is used to process potentially tainted data.

- Суть XXE-атаки
- Примеры уязвимого кода

Анализатор обнаружил использование небезопасно сконфигурированного XML-парсера, который обрабатывает данные, полученные из внешнего источника. Это может сделать приложение уязвимым к XXE-атаке.

XXE-атаки выделены в отдельную категорию рисков в OWASP Top 10 Application Security Risks 2017: A4:2017 – XML External Entities (XXE) и включены в категорию A05:2021 – Security Misconfiguration OWASP Top 10 2021.

## Суть XXE-атаки

Стандарт XML предусматривает использование DTD (document type definition). DTD даёт возможность определять и использовать XML-сущности. Сущности могут быть как полностью определены внутри документа (например, представлять собой какую-то строку), так и ссылаться на какой-то внешний ресурс. Отсюда и происходит название XXE-атаки: XML eXternal Entities.

Внешние сущности могут быть определены через URI, вследствие чего XML-парсер может обработать этот URI и подставить полученное содержимое в XML-документ.

Пример XML-документа, в котором определена внешняя сущность:

    <?xml version="1.0" encoding="utf-8" ?>
    <!DOCTYPE foo [
      <!ENTITY xxe SYSTEM "file://D:/XXETarget.txt">
    ]>
    <foo>&xxe;</foo>

Здесь определена сущность '&xxe;'. При обработке этого XML парсер подставит вместо '&xxe;' содержимое файла 'D:\XXETarget.txt'.

Таким образом, атака возможна, если:

- злоумышленник может передать приложению XML-файл с внешними сущностями, и приложение выполнит парсинг этого файла;
- XML-парсер имеет небезопасную конфигурацию;
- данные парсинга (значения сущностей) могут попасть обратно к злоумышленнику.

Как следствие, злоумышленник может, например, раскрыть содержимое данных с машины, на которой исполняется приложение и которая занимается парсингом XML-файла.

## Примеры уязвимого кода

PVS-Studio выдаст предупреждение, если обнаружит в коде небезопасно сконфигурированный XML-парсер, который обрабатывает данные, которые могут быть получены из внешнего источника.

Рассмотрим простой пример. Есть приложение, которое принимает запросы в виде XML-файлов и обрабатывает товары с соответствующим идентификатором. Если идентификатор задан неверно, приложение сообщает об этом.

Формат XML-файла, с которым работает приложение:

    <?xml version="1.0" encoding="utf-8" ?>
    <shop>
      <itemID>62</itemID>
    </shop>

Допустим, обработкой занимается следующий код:

    static void ProcessItemWithID(String pathToXmlFile)
    {
      XmlReaderSettings settings = new XmlReaderSettings()
      {
        XmlResolver = new XmlUrlResolver(),
        DtdProcessing = DtdProcessing.Parse
      };

      using (var fileReader = File.OpenRead(pathToXmlFile))
      {
        using (var reader = XmlReader.Create(fileReader, settings))
        {
          while (reader.Read())
          {
            if (reader.Name == "itemID")
            {
              var itemIDStr = reader.ReadElementContentAsString();
              if (long.TryParse(itemIDStr, out var itemIDValue))
              {
                // Process item with the 'itemIDValue' value
                Console.WriteLine(
                  $"An item with the '{itemIDValue}' ID was processed.");
              }
              else
              {
                Console.WriteLine($"{itemIDStr} is not valid 'itemID' value.");
              }
            }
          }
         }
      }
    }

Для приведённого выше XML-файла приложение распечатает следующую строку:

    An item with the '62' ID was processed.

Если вместо номера в ID будет записано что-то другое (например, строка "Hello world"), приложение сообщит об ошибке:

    "Hello world" is not valid 'itemID' value.

Несмотря на то, что код делает то, что от него ожидается, он уязвим к XXE-атакам за счёт соблюдения всех перечисленных ранее факторов:

- содержимое XML поступает от пользователя;
- XML-парсер сконфигурирован таким образом, чтобы обрабатывать внешние сущности;
- вывод может передаваться обратно пользователю.

Ниже представлен XML-файл, через который можно скомпрометировать данный код:

    <?xml version="1.0" encoding="utf-8" ?>
    <!DOCTYPE foo [
      <!ENTITY xxe SYSTEM "file://D:/MySecrets.txt">
    ]>
    <shop>
      <itemID>&xxe;</itemID>
    </shop>

В этом файле объявляется внешняя сущность 'xxe', которая будет обработана парсером. Вследствие этого содержимое файла 'D:/MySecrets.txt' (например, такое: 'This is an XXE attack target.'), находящегося на машине, где запущено приложение, будет выдано пользователю:

    This is an XXE attack target. is not valid 'itemID' value.

Для того, чтобы обезопаситься от подобной атаки, можно запретить обработку внешних сущностей (присвоить свойству 'XmlResolver' значение 'null'), а также запретить или игнорировать обработку DTD (записать в свойство 'DtdProcessing' значение 'Prohibit' или 'Ignore' соответственно).

Пример безопасных настроек:

    XmlReaderSettings settings = new XmlReaderSettings()
    {
      XmlResolver = null,
      DtdProcessing = DtdProcessing.Prohibit
    };

Обратите внимание, что при использовании различных типов, уязвимость к XXE-атакам может выглядеть по-разному. Например, следующий код также уязвим к XXE-атаке:

    static void ProcessXML(String pathToXmlFile)
    {
      XmlDocument xmlDoc = new XmlDocument();
      xmlDoc.XmlResolver = new XmlUrlResolver();

      using (var xmlStream = File.OpenRead(pathToXmlFile))
      {
        xmlDoc.Load(xmlStream);
        Console.WriteLine(xmlDoc.InnerText);
      }
    }

Здесь загрузка XML происходит через экземпляр типа 'XmlDocument'. При этом для 'XmlResolver' явно выставлено опасное значение, а обработка DTD включена неявно. Чтобы запретить обработку внешних сущностей, достаточно записать в свойство 'XmlResolver' значение 'null'.

Анализатор также учитывает и межпроцедурные вызовы. Рассмотрим пример:

    static FileStream GetXmlFileStream(String pathToXmlFile)
    {
      return File.OpenRead(pathToXmlFile);
    }

    static XmlDocument GetXmlDocument()
    {
      XmlDocument xmlDoc = new XmlDocument()
      {
        XmlResolver = new XmlUrlResolver()
      };

      return xmlDoc;
    }

    static void LoadXmlInternal(XmlDocument xmlDoc, Stream input)
    {
      xmlDoc.Load(input);
      Console.WriteLine(xmlDoc.InnerText);
    }

    static void XmlDocumentTest(String pathToXmlFile)
    {
      using (var xmlStream = GetXmlFileStream(pathToXmlFile))
      {
        var xmlDoc = GetXmlDocument();
        LoadXmlInternal(xmlDoc, xmlStream);
      }
    }

В данном случае анализатор выдаст предупреждение на вызов метода 'LoadXmlInternal', так как отследит, что:

- парсер, полученный из метода 'GetXmlDocument', может обрабатывать внешние сущности;
- поток, полученный из метода 'GetXmlStream', содержит данные, полученные из внешнего источника (прочитанные из файла);
- парсер и 'заражённые' данные передаются в метод 'LoadXmlInternal', где выполняется обработка XML-файла.

Стоит отметить, что анализатор также считает источниками небезопасных данных параметры методов, доступных из других сборок. Более подробно эта тема раскрыта в заметке "Почему важно проверять значения параметров общедоступных методов".

Например, на следующий код будет выдано предупреждение низкого уровня достоверности, так как источник небезопасных данных – параметр публично-доступного метода:

    public static void XmlDocumentTest(Stream xmlStream)
    {
      XmlDocument doc = new XmlDocument()
      {
        XmlResolver = new XmlUrlResolver()
      };

      doc.Load(xmlStream);
      Console.WriteLine(doc.InnerText);
    }

Обратите внимание, что настройки некоторых XML-парсеров менялись в разных версиях .NET Framework.

Рассмотрим следующий фрагмент кода:

    static void XmlDocumentTest(String pathToXml)
    {
      var xml = File.ReadAllText(pathToXml);
      XmlDocument doc = new XmlDocument();

      doc.LoadXml(xml);
      Console.WriteLine(doc.InnerText);
    }

Данный код является устойчивым к XXE-атакам в .NET Framework 4.5.2 и более новых версиях, так как свойство 'XmlResolver' по умолчанию имеет значение 'null'. Как следствие, внешние сущности не будут обработаны.

В версиях .NET Framework 4.5.1 и более старых данный код уязвим к XXE-атакам, так как по умолчанию 'XmlResolver' не равен 'null' и обрабатывает внешние сущности.

PVS-Studio также учитывает дефолтные настройки парсеров в зависимости от того, какая версия .NET Framework / .NET используется в анализируемом проекте.

Общая рекомендация по защите от XXE-атак – следить за тем, чтобы обработка DTD была отключена; обработка внешних сущностей – запрещена. В разных XML-парсерах настройки могут немного отличаться, но, как правило, за это отвечают свойства 'DtdProcessing' ('ProhibitDtd' в более старых версиях .NET Framework) и 'XmlResolver'.

Выявляемые диагностикой ошибки классифицируются согласно ГОСТ Р 71207–2024 как критические и относятся к типу: Ошибки непроверенного использования чувствительных данных (ввода пользователя, файлов, сети и пр.).

Данная диагностика классифицируется как:

CWE-611 OWASP-5.5.2