JBoss7中调用XMLSignature.validate报错Current Node: [#document: null], type:9
解决JBoss7下XML签名验证崩溃问题(报错
Current Node: [#document: null], type: 9) 我之前在JBoss7环境做XML签名验证时碰到过一模一样的报错,结合你的代码和XML内容来看,这个问题大概率是XPath变换的上下文处理异常或者JBoss自带XML解析器与XMLDSig的兼容性冲突导致的。下面是我整理的排查思路和解决方案:
问题定位
先看你XML里的签名变换规则:
<Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116"> <XPath>ancestor-or-self::Signature</XPath> </Transform>
这个XPath是用来排除Signature节点本身的,但JBoss自带的DOM解析器(比如特定版本的Xerces)在处理这个规则时,可能会把上下文节点错误切换到#document节点,进而触发类型不匹配的崩溃。
另外你的代码里有个冗余操作:dbf.setNamespaceAware(true);被重复调用了一次,虽然不影响功能,但可以清理掉让代码更简洁。
解决方案
方案1:手动指定XPath变换的上下文节点
默认的DOMValidateContext可能没有正确绑定XPath的作用范围,你可以手动把验证上下文绑定到XML的根节点(也就是<ObjectMessage>),避免解析器误跳到document节点。修改后的代码如下:
File fff = new File("S:\\signeData.xml"); FileInputStream fileInputStream = new FileInputStream(fff); long byteLength = fff.length(); byte[] filecontent = new byte[(int) byteLength]; fileInputStream.read(filecontent, 0, (int) byteLength); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); Document doc = dbf.newDocumentBuilder().parse(new ByteArrayInputStream(filecontent)); // 获取最后一个Signature节点 NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature"); Node signatureNode = nl.item(nl.getLength() - 1); // 获取XML根节点作为XPath变换的上下文 Node rootNode = doc.getDocumentElement(); String providerName = System.getProperty("jsr105Provider", "org.apache.jcp.xml.dsig.internal.dom.XMLDSigRI"); XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM", (Provider) Class.forName(providerName).newInstance()); // 创建验证上下文并绑定根节点 DOMValidateContext valContext = new DOMValidateContext(new XmlUtil.X509KeySelector(), signatureNode); valContext.setProperty("javax.xml.crypto.dsig.cacheReference", Boolean.TRUE); valContext.setNode(rootNode); // 关键:指定XPath的作用上下文 XMLSignature signature = fac.unmarshalXMLSignature(valContext); res = signature.validate(valContext);
方案2:替换JBoss的XML解析器版本
JBoss7自带的Xerces版本可能和XMLDSig的实现存在兼容性问题,你可以:
- 在项目的
WEB-INF/lib中引入独立的xercesImpl.jar(推荐版本2.12.1)和xml-apis.jar,让应用优先使用这个版本的解析器; - 或者修改JBoss的模块配置文件
modules/system/layers/base/org/apache/xerces/main/module.xml,替换成更新的Xerces包,并确保export="true"配置项开启。
方案3:先对XML做C14N规范化再验证
有时候XML在解析过程中会被自动修改换行、空格等格式,导致签名验证失败。你可以先按照签名时用的规范化算法(http://www.w3.org/TR/2001/REC-xml-c14n-20010315)预处理XML,再进行验证:
// 对根节点做C14N规范化 Canonicalizer c14n = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS); byte[] canonicalizedBytes = c14n.canonicalizeSubtree(rootNode); Document canonicalDoc = dbf.newDocumentBuilder().parse(new ByteArrayInputStream(canonicalizedBytes)); // 用规范化后的文档重新获取Signature节点并验证 NodeList canonicalNl = canonicalDoc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature"); Node canonicalSignatureNode = canonicalNl.item(canonicalNl.getLength() - 1); DOMValidateContext valContext = new DOMValidateContext(new XmlUtil.X509KeySelector(), canonicalSignatureNode); valContext.setProperty("javax.xml.crypto.dsig.cacheReference", Boolean.TRUE); XMLSignature signature = fac.unmarshalXMLSignature(valContext); res = signature.validate(valContext);
验证建议
- 优先尝试方案1,这是最轻量化的修改,不需要调整依赖或服务器配置;
- 如果方案1无效,再试方案3,排除XML格式不一致的问题;
- 最后考虑方案2,解决JBoss底层解析器的兼容性问题。
我之前在JBoss7.1.1环境下遇到这个报错时,用方案1就顺利解决了,你可以先试试这个方法。
内容的提问来源于stack exchange,提问作者Thế Hải Nguyễn
相关产品推荐
相关产品推荐

