如何保护球衣服务器上的 xml 请求?

how to protect xml requests on a jersey server?

我目前有一个使用 jersey-server 1.1 框架创建的简单 xml 端点(示例)。它使用以下符号消耗和生成 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;
]>

我想要一种方法来保护服务器并且不允许它调用其他 servers/serve up 文件给攻击者。

有没有办法做到这一点,因为包括 XML 阅读在内的所有内容都来自框架本身? @Consumes(MediaType.APPLICATION_XML)

我认为我可以做到这一点的唯一方法是在请求的主体上使用正则表达式以某种方式使用过滤器?阻止 DOCTYPESYSTEMENTITY 请求和 return 错误,但我想知道是否有更简单的方法来执行此操作并覆盖 [=13= 的默认行为]?

我将只解决 XXE 问题,因为关于其他需要解决的特定 authentication/authorization 问题,问题并不完全清楚。

Blaise's approach to prevent XXE with basic JAXB 开始,需要做的是获得 lower-level 对提供的 XML 的访问权限。好在 Jersey 开箱即用地支持这一点。一种方法是用 StreamSource 替换您的 Employee 参数。

  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();
    
    }
    

您需要禁用 http://apache.org/xml/features/nonvalidating/load-external-dtdhttp://xml.org/sax/features/validation 功能,因为 described in details

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

Java system properties can be manipulated programmatically at runtime, I came up with the idea to dynamically replace the current document builder factory with a wrapper that sets certain features on new instances of the document builder factory. Setting those features were said to cause references to DTD documents to be ignored when parsing XML that contained such references.

:

  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);

我遇到了同样的问题,不幸的是,上述解决方案仅有条件地适用于只有 XML 传输类型的服务。同时支持 XML 和 JSON 的服务执行效率不高。

我在 jersey 存储库的 Github 上发现了这个讨论 https://github.com/eclipse-ee4j/jersey/issues/3446,这个问题似乎已经在 2020 年 3 月以来的 2.33 版本中得到修复:

Upgade Jersey dependency to 2.33

我觉得比修改每一个服务容易多了