В настоящее время у меня есть простая конечная точка xml (пример), созданная с использованием инфраструктуры jersey-server 1.1. он потребляет и производит XML, используя следующие обозначения:

@POST
@Path("/post")
@Consumes(MediaType.APPLICATION_XML)
@Produces(MediaType.APPLICATION_XML)
public Response getEmployee(Employee employee) {
     return Response.status(Status.OK).entity(employee).build();
}

Однако конечная точка уязвима для атак XXE. (пример) также возможно заставить мой сервер говорить, чтобы запросить любую конечную точку, используя эту запись ...

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [
<!ENTITY % a SYSTEM "file:///etc/passwd">
%a;
]>

Мне нужен способ защитить сервер и не позволять ему вызывать другие серверы / подавать файлы злоумышленникам.

Есть ли способ сделать это, поскольку все, включая чтение XML, исходит из самой платформы? @Consumes(MediaType.APPLICATION_XML)

Единственный способ сделать это - использовать регулярное выражение в теле запроса как-то с фильтром? заблокировать DOCTYPE, SYSTEM, ENTITY запросы и вернуть ошибку, но мне интересно, есть ли более простой способ сделать это и переопределить поведение по умолчанию @Consumes(MediaType.APPLICATION_XML)?

3
user2950720 29 Май 2019 в 23:09

2 ответа

Лучший ответ

Я собираюсь рассмотреть только проблему XXE, потому что вопрос не совсем ясен относительно других конкретных проблем аутентификации / авторизации.

Начиная с подхода Blaise по предотвращению XXE с помощью базового JAXB, что нужно сделать, чтобы получить низкоуровневый доступ к предоставленному XML. Хорошо, что Джерси поддерживает это из коробки. Один из способов сделать это - заменить аргумент Employee на StreamSource.

  1. Сначала возьмите существующий JAXBContext:

    private final @Context Providers providers; //full list of all providers available
    
  2. Измените ваш интерфейс так, чтобы он принимал StreamSource, чтобы у вас был доступ к необработанному входящему XML:

    @POST
    @Path("/post")
    @Consumes(MediaType.APPLICATION_XML)
    @Produces(MediaType.APPLICATION_XML)
    public Response getEmployee(StreamSource employeeStreamSource)
    
  3. Сконфигурируйте демаршаллер JAXBContext для игнорирования DTD:

    public Response getEmployee(StreamSource employeeStreamSource){
        //we try to get a hold of the JAXBContext
        ContextResolver<JAXBContext> jaxbResolver = provider.getContextResolver(JAXBContext.class, MediaType.APPLICATION_XML_TYPE);
        JAXBContext jaxbContext= null;
        if(null != jaxbResolver) {
            jaxbContext = jaxbResolver.getContext(Employee.class);
        }
        if(null == jaxbContext) {
            jaxbContext = JAXBContext.newInstance(Employee.class);
        }
    
        XMLInputFactory xif = XMLInputFactory.newFactory();
        xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); //Don't blindly parse entities
        xif.setProperty(XMLInputFactory.SUPPORT_DTD, false); //suppress DTD
        XMLStreamReader xsr = xif.createXMLStreamReader(employeeStreamSource); //beging parsing incoming XML
    
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        Employee employee= (Employee) unmarshaller.unmarshal(xsr);  //manually unmarshal
    
        return Response.status(Status.OK).entity(employee).build();
    
    }
    
1
kolossus 3 Июн 2019 в 06:10

Вам необходимо отключить функции http://apache.org/xml/features/nonvalidating/load-external-dtd и http://xml.org/sax/features/validation как подробно описан

  /* Set features to turn off loading of external DTDs. */
    mDocumentBuilderFactoryDelegateBuilderFactory.setFeature(
       LOADEXTERNALDTD_FEATURE, false);
    mDocumentBuilderFactoryDelegateBuilderFactory.setFeature(
       XML_VALIDATION_FEATURE, false);

Системными свойствами Java можно манипулировать программно во время выполнения, и мне пришла в голову идея динамически заменить текущую фабрику компоновщика документов оболочкой, которая устанавливает определенные функции в новых экземплярах фабрики компоновщика документов. Было сказано, что установка этих функций приводит к тому, что ссылки на документы DTD игнорируются при разборе XML, содержащего такие ссылки.

более короткий код:

  DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
     dbf.setValidating(false);
     dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
     DocumentBuilder db = dbf.newDocumentBuilder();
     Document doc = db.parse(iStream);
0
user7294900 3 Июн 2019 в 15:16