背景:
我正在使用 JAXB 将 XML 解组为 Java 对象。最初,我只使用 JAXB 来执行解组。然后对代码进行了静态分析,并提出了 XML 外部实体注入的高危问题。经过一番研究后,我发现了一个建议(https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#JAXB_Unmarshaller)使用配置为防止解析外部实体的解析器。提供了该怎么做的示例:
//Disable XXE
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature("http://xml.org/sax/features/external-general-entities", false);
spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
//Do unmarshall operation
Source xmlSource = new SAXSource(spf.newSAXParser().getXMLReader(), new InputSource(new StringReader(xml)));
JAXBContext jc = JAXBContext.newInstance(Object.class);
Unmarshaller um = jc.createUnmarshaller();
um.unmarshal(xmlSource);
Run Code Online (Sandbox Code Playgroud)
我没有完全按照所示方式完成此操作,但我相信我实际上已经做了相同的操作:
XMLReader reader = getXMLReader();
if (reader == null) {
logger.warn("Unable to create XML reader");
return;
}
JAXBContext context = JAXBContext.newInstance(messageClass);
Unmarshaller unmarshaller = context.createUnmarshaller();
for (File file : files) {
try {
InputSource source = new InputSource(new FileReader(file));
Source xmlSource = new SAXSource(reader, source);
JAXBElement<? extends BaseType> object =
(JAXBElement<? extends BaseType>) unmarshaller.unmarshal(xmlSource);
messages.add(object.getValue());
} catch (FileNotFoundException e) {
logger.error("Exception", e);
}
}
...
private XMLReader getXMLReader() {
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
} catch (SAXNotRecognizedException | SAXNotSupportedException
| ParserConfigurationException e) {
logger.error("Exception", e);
}
XMLReader reader = null;
try {
reader = factory.newSAXParser().getXMLReader();
} catch (SAXException | ParserConfigurationException e) {
logger.error("Exception", e);
}
return reader;
}
Run Code Online (Sandbox Code Playgroud)
问题:
实施更正后,当程序尝试读取 XML 时,我现在收到一个解组异常:
javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"ns1:TypeXYZ"). Expected elements are <{protected namespace URI}TypeABC>,...<{protected namespace URI}TypeXYZ>,...
Run Code Online (Sandbox Code Playgroud)
在上面的修复之前,我只是使用 JAXB 进行解组,它能够正确解析提供的 XML,没有任何问题。
我假设 SAX 解析器期望 XML 提供缺少的额外信息,或者需要将其配置为忽略它所抱怨的任何内容。我尝试了一些其他“功能”(http://xml.org/sax/features/namespace-prefixes=true和http://xml.org/sax/features/validation=false),但这并没有解决问题。
我无法控制定义 XML 类型的 XML 模式,也无法控制如何生成相应的 Java 类。
任何可以帮助我了解正在发生的事情并帮助我解决这个问题的信息,将不胜感激。
经过一些实验后,我能够通过设置以下功能来解决该错误:
factory.setFeature("http://xml.org/sax/features/validation", false);
factory.setFeature("http://xml.org/sax/features/namespaces", true);
factory.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
Run Code Online (Sandbox Code Playgroud)