You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

验证JAXB反序列化禁用Schema时未加载XSD的方法及安全问询

验证JAXB禁用Schema验证时未访问XSD文件的方法

前置信息

以下内容关联Stack Overflow相关问题,给定的Schema文件customer.xsd内容如下:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:simpleType name="stringMaxSize5">
        <xs:restriction base="xs:string">
            <xs:maxLength value="5"/>
        </xs:restriction>
    </xs:simpleType>
    <xs:element name="customer">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="name" type="stringMaxSize5"/>
                <xs:element ref="phone-number" maxOccurs="2"/>
             </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="phone-number">
        <xs:complexType>
            <xs:sequence/>
        </xs:complexType>
    </xs:element>
</xs:schema>

待反序列化的XML文档input.xml内容:

<customer
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="./customer.xsd">
    <name>Jane Doe</name>
    <phone-number/>
    <phone-number/>
    <phone-number/>
</customer>

JAXB反序列化代码:

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;

public class Unmarshal {

    @XmlRootElement(name = "customer")
    public static class Customer {
        public String name;
        @XmlElement(name="phone-number")
        public List<PhoneNumber> phoneNumbers = new ArrayList<PhoneNumber>();
    }

    public static class PhoneNumber {}

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Customer.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        unmarshaller.setSchema(null);
        Customer customer = (Customer) unmarshaller.unmarshal(new File("input.xml"));
        System.out.println(customer.name);
    }

}

上述代码中,XML存在两处验证错误:

cvc-maxLength-valid: Value 'Jane Doe' with length = '8' is not facet-valid with respect to maxLength '5' for type 'stringMaxSize5'.xml(cvc-maxLength-valid)
cvc-type.3.1.3: The value 'Jane Doe' of element 'name' is not valid.xml(cvc-type.3.1.3)

以及:

cvc-complex-type.2.4.f: 'phone-number' can occur a maximum of '2' times in the current sequence. This limit was exceeded. No child element is expected at this point.xml(cvc-complex-type.2.4.f)

但因为代码中通过unmarshaller.setSchema(null);禁用了Schema验证,XML仍能被正常反序列化为Customer实例。现在需要明确:如何证明JVM在反序列化过程中未访问customer.xsd文件?避免盲目信任JVM不会加载XML中的XSD引用,以此评估XXE攻击风险。


验证方法

1. 移除/重命名XSD文件测试

直接删除或者重命名customer.xsd文件,然后运行原反序列化代码。如果代码能正常执行,输出Jane Doe且无文件找不到的异常,说明JVM完全没有尝试加载该XSD文件——若存在访问行为,会抛出FileNotFoundException或XML解析相关错误。

2. 监控文件系统访问

  • Windows平台:使用Process Monitor工具,过滤当前Java进程对customer.xsd的访问请求,若没有相关记录则证明未访问;
  • Linux/macOS平台:用strace(Linux)或dtrace(macOS)跟踪Java进程的文件操作系统调用,查看是否存在打开customer.xsd的行为,无相关调用则说明未访问。

3. 配置XML解析器,强制禁用外部引用

即使禁用了Schema验证,XML解析器仍可能解析外部实体。可以通过配置JAXB使用的解析器,从根源上杜绝外部文件加载,同时防范XXE攻击:

import javax.xml.XMLConstants;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.XMLReader;

// 在创建Unmarshaller后添加以下配置
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
spf.setFeature("http://xml.org/sax/features/external-general-entities", false);
spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
XMLReader xmlReader = spf.newSAXParser().getXMLReader();
unmarshaller.setUnmarshallerHandler(xmlReader.getContentHandler());

配置后,解析器会直接忽略XML中的XSD引用及其他外部实体,彻底消除风险。

4. 启用JVM调试日志

添加JVM启动参数开启XML组件调试日志:

-Djavax.xml.debug=all

运行程序后查看日志输出,若没有任何关于加载customer.xsd的条目,即可证明JVM未尝试访问该文件。


内容的提问来源于stack exchange,提问作者Jesús Zazueta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 04:22:11