Предотвратить атаку XXE с помощью JAXB

Недавно мы провели аудит безопасности нашего кода, и одна из проблем заключается в том, что наше приложение подвержено атаке Xml eXternal Entity (XXE).

По сути, приложение представляет собой калькулятор, который получает входные данные в виде XML через веб-службу.

Вот пример такой атаки XXE на наше приложение:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header/>
   <soapenv:Body>
      <foo:calculateStuff>
         <!--Optional:-->
         <xmlInput><![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE currency [  
   <!ENTITY include SYSTEM "file:///d:/" >]>
<calcinput>...</calcinput>
]]></xmlInput>
      </foo:calculateStuff>
   </soapenv:Body>
</soapenv:Envelope>

Как видите, мы можем ссылаться на объект, указывающий на внешний файл ("file:///d:/").

Что касается самого ввода XML (часть <calcinput>...</calcinput>), он неупорядочен с помощью JAXB (v2.1). Часть веб-сервиса основана на jaxws-rt (2.1).

Что мне нужно сделать, чтобы обезопасить свой веб-сервис?


person Romain Linsolas    schedule 19.10.2012    source источник


Ответы (1)


JAXB

Вы можете предотвратить атаку Xml eXternal Entity (XXE) путем демаршалинга из XMLStreamReader, для которого свойства IS_SUPPORTING_EXTERNAL_ENTITIES и / или XMLInputFactory.SUPPORT_DTD установлены на false.

JAX-WS

Реализация JAX-WS должна позаботиться об этом за вас. Если этого не произойдет, я бы рекомендовал открыть ошибку против конкретного внедрения.


ПРИМЕР

Демо

package xxe;

import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Customer.class);

        XMLInputFactory xif = XMLInputFactory.newFactory();
        xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
        xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
        XMLStreamReader xsr = xif.createXMLStreamReader(new StreamSource("src/xxe/input.xml"));

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Customer customer = (Customer) unmarshaller.unmarshal(xsr);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(customer, System.out);
    }

}

input.xml

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

<?xml version="1.0"?>
<!DOCTYPE customer
[
<!ENTITY name SYSTEM "/Users/bdoughan/Examples/src/xxe/">
]
>
<customer>
  <name>&name;</name>
</customer>

Клиент

package xxe;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Customer {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

Вывод - конфигурация по умолчанию

По умолчанию объект будет разрешен.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer>
    <name>Customer.java
Demo.java
input.xml
</name>
</customer>

Вывод, когда для свойства XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES установлено значение false

Когда это свойство установлено, сущность не разрешается.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer>
    <name></name>
</customer>

Вывод, когда для свойства XMLInputFactory.SUPPORT_DTD установлено значение false

Когда это свойство установлено, выдается исключение при попытке разрешить сущность.

Exception in thread "main" javax.xml.bind.UnmarshalException
 - with linked exception:
[javax.xml.stream.XMLStreamException: ParseError at [row,col]:[8,15]
Message: The entity "name" was referenced, but not declared.]
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.handleStreamException(UnmarshallerImpl.java:436)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:372)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:342)
    at xxe.Demo.main(Demo.java:18)
Caused by: javax.xml.stream.XMLStreamException: ParseError at [row,col]:[8,15]
Message: The entity "name" was referenced, but not declared.
    at com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.next(XMLStreamReaderImpl.java:598)
    at com.sun.xml.bind.v2.runtime.unmarshaller.StAXStreamConnector.bridge(StAXStreamConnector.java:196)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:370)
    ... 2 more
person bdoughan    schedule 19.10.2012
comment
Спасибо за действительно подробный ответ! У меня все еще есть небольшая проблема: когда я устанавливаю xif.setProperty(XMLInputFactory.SUPPORT_DTD, false); , я получаю следующее ParseError: Включенный объект был указан, но не объявлен. Но если я удалю это свойство (но оставлю первое), XML будет правильно проанализирован. Любая идея? - person Romain Linsolas; 22.10.2012
comment
@BlaiseDoughan есть ли способ включить сущности, но ограничить их значением, скажем, 5 или 10? Мы получаем запросы, которые содержат & в некоторых полях, вводимых пользователем. - person asgs; 19.11.2013
comment
@asgs - вы можете указать предел расширения сущности на уровне виртуальной машины. См .: blog.bdoughan.com/2011/03/ - person bdoughan; 19.11.2013
comment
@BlaiseDoughan, безопасно ли / потокобезопасно создавать один надежно настроенный XMLInputFactory, а затем создавать новый XMLStreamReader для каждого экземпляра документа? - person doughgle; 21.03.2016
comment
У меня есть веб-сервис Spring MVC, в котором я настроил маршалинг и демаршалинг, как указано выше, но я все еще получаю инъекцию внешнего объекта XML в инструменте Acunetix. Пожалуйста, помогите! - person shraddha bhardwaj; 31.03.2016
comment
@romaintaz Вы написали, что хотите обезопасить веб-сервис. Как можно использовать XMLInputFactory xif = XMLInputFactory.newFactory();? Я имею в виду - парсинг выполняется контейнером, и вы получаете объект ... - person user1414745; 04.08.2016
comment
На этом веб-сайте объясняется, как заблокировать его на нескольких основных платформах Java. . - person Sameer Puri; 10.08.2016
comment
Это отлично работает, я пробовал способ, упомянутый в owasp.org/index.php / но это не сработало .. большое спасибо! - person Shessuky; 27.12.2018
comment
@bdoughan вы используете input.xml как строку, но я использую объект класса SoapHeader, например xif.createXMLStreamReader (soapHeader.getSource ()), но я получаю такое же исключение в инструменте kiwan XML enetity Injection. - person Hitesh; 06.11.2019
comment
@ user1414745, когда я конвертирую soapHeader.getSource () в строку с помощью объекта TransformerFactory, он дает мне ошибку java.lang.IllegalArgumentException: Unknown configuration property http://javax.xml.XMLConstants/property/accessExternalDTD - person Hitesh; 06.12.2019
comment
@bdoughan Не уверен, что вы это увидите ... но я использую ByteArrayInputStream в unmarshal (). Можно ли использовать предложенный вами ответ и использовать XMLStreamReader? Кроме того, не могли бы вы подробнее рассказать о файле input.xml? Мой вопрос можно найти: stackoverflow.com/ questions / 65295943 / - person Jonathan Hagen; 14.12.2020