[英]Broken Digital Signature due to altered XML attributes order
我正在 Java 中开发一个 SOAP 网络服务器,其中我的响应必须加上时间戳和签名。 要签名的节点是 BODY 和 TIMESTAMP。
问题是XmlSignature.sign方法解组这些节点,将命名空间属性放置在 BODY 和 TIMESTAMP 标记中的 Id 属性之前,并且由 JAX-WS 解组的出站响应字符串将命名空间属性放置在 Id之后。
结果,这些节点的计算摘要值是无效的,即:
Actual Digest: ljf4iIFTgpHUDKtLjYJEto9Ro5k=
Expected Digest: iIYWShXDG4o8f/9L08d+apVsGx0=
我想如果我可以指定解组器的属性顺序(在签名或响应消息中),我也可以使顺序匹配,但我没有设法做到这一点。
我测试了一个 SOAPHandler 来拦截响应,但我发现无法更改消息属性顺序。
这是签名类生成的节点时间戳的 XML 代码:
<wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="TS-1000">
<wsu:Created>2019-09-19T10:00:00.000Z</wsu:Created>
<wsu:Expires>2019-09-19T10:05:00.000Z</wsu:Expires>
</wsu:Timestamp>
这是响应中发送的 TIMESTAMP 节点的 XML 代码:
<wsu:Timestamp wsu:Id="TS-1000" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsu:Created>2019-09-19T10:00:00.000Z</wsu:Created>
<wsu:Expires>2019-09-19T10:05:00.000Z</wsu:Expires>
</wsu:Timestamp>
BODY 节点也是如此。 签名:
<S:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Body-1000">
<AsignacionNotarioResponse xmlns="http://ancert.notariado.org/XML">
<CodigoRespuesta>0</CodigoRespuesta>
<IdNotificacionCGN>371003</IdNotificacionCGN>
</AsignacionNotarioResponse>
</S:Body>
发送:
<S:Body wsu:Id="Body-1000" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<AsignacionNotarioResponse xmlns="http://ancert.notariado.org/XML">
<CodigoRespuesta>0</CodigoRespuesta>
<IdNotificacionCGN>371003</IdNotificacionCGN>
</AsignacionNotarioResponse>
</S:Body>
SOAP 响应中的完全安全 header :
<SOAP-ENV:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="X509Token-1000" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">MIIHdDCCBVygAwIBAgIQDOHw8dChstzYGWhilSpZhjANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMCRVMxQTA
...OMITED... ==</wsse:BinarySecurityToken>
<wsu:Timestamp wsu:Id="TS-1000" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsu:Created>2019-09-19T10:00:00.000Z</wsu:Created>
<wsu:Expires>2019-09-19T10:05:00.000Z</wsu:Expires>
</wsu:Timestamp>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#Body-1000">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>5yQ7ZdxYjr3pxySKrVbA0/98a4s=</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#TS-1000">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>sEY89etI7c+uGrFPh7W59nu/4ac=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>CFsbgg+AbV6iiMqWbiZmCacMeZcmcrsW2Eub5B1bUzLsCnygrFZDv/WEI5R3CyS6nvSPNvr7TKXg
W235F2mPYSUXFLun/IPYU+0BsMYMLxFF4qMX2pXRFgtXWt9zmhBIf1rl+iuG8mTqUGR0eYMrxW0B
KxpAIgAEAUZmWuP7vHcnfPrEhR2+N7S4BOVloSlVFoekh1tr0njH1RDR3WYyP8XszeZdzaQmDHKl
QONJQ5zjpaHk/TCMLhiSib+aDAeF4MaT73eo68rM5HNyD4b5EKty+z+bE6GPsS/lR8TFbP0uwLDz
9uKiM0l7fM1ctEd3RORkveXvSXGZlKQ+HKmISA==</ds:SignatureValue>
<ds:KeyInfo Id="KI-1000">
<wsse:SecurityTokenReference wsu:Id="STR-1000" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Reference URI="#X509Token-1000"/>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
</wsse:Security>
</SOAP-ENV:Header>
这是我用于将数字签名添加到 SOAP 消息的例程:
/**
* Genera la firma del mensaje SOAP.
*
* @param privateKey Clave privada
* @param soapBody Cuerpo de la petición SOAP
* @param nodoSecurity Nodo Security
* @param nodoSecurityTokenReference Nodo SecurityTokenReference
* @param nodoTimestamp Nodo timestamp
*
* @throws CgnException Error al generar la firma del mensaje
*/
private static void crearFirmaSeparada(PrivateKey privateKey, SOAPBody soapBody, SOAPElement nodoSecurity, SOAPElement nodoSecurityTokenReference,
SOAPElement nodoTimestamp) throws CgnException
{
String uri_algoritmo_digest = "http://www.w3.org/2000/09/xmldsig#sha1";
String uri_algoritmo_firma = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
String uri_algoritmo_transformacion = "http://www.w3.org/2001/10/xml-exc-c14n#";
String uri_algoritmo_canonizacion = "http://www.w3.org/2001/10/xml-exc-c14n#";
try {
// Creamos un el DOM XMLSignatureFactory que utilizaremos para generar la firma
String providerName = System.getProperty("jsr105Provider", "org.jcp.xml.dsig.internal.dom.XMLDSigRI");
Provider provider = (Provider) Class.forName(providerName).newInstance();
XMLSignatureFactory xmlSignatureFactory = XMLSignatureFactory.getInstance("DOM", provider);
// Digest method
javax.xml.crypto.dsig.DigestMethod digestMethod = xmlSignatureFactory.newDigestMethod(uri_algoritmo_digest, null);
List <Transform> l_transformaciones = new ArrayList();
// Transformaciones
Transform envTransform = xmlSignatureFactory.newTransform(uri_algoritmo_transformacion, (TransformParameterSpec) null);
l_transformaciones.add(envTransform);
// Referencias al timestamp y al body
String id_key_info = "KI-1000";
List <Reference> l_referencias = new ArrayList();
Reference refTS = xmlSignatureFactory.newReference("#TS-1000", digestMethod, l_transformaciones, null, null);
Reference refBody = xmlSignatureFactory.newReference("#Body-1000", digestMethod, l_transformaciones, null, null);
l_referencias.add(refBody);
l_referencias.add(refTS);
CanonicalizationMethod cm = xmlSignatureFactory.newCanonicalizationMethod(uri_algoritmo_canonizacion, (C14NMethodParameterSpec) null);
SignatureMethod sm = xmlSignatureFactory.newSignatureMethod(uri_algoritmo_firma, null);
SignedInfo signedInfo = xmlSignatureFactory.newSignedInfo(cm, sm, l_referencias);
DOMSignContext signContext = new DOMSignContext(privateKey, nodoSecurity);
signContext.setDefaultNamespacePrefix("ds");
signContext.putNamespacePrefix("http://www.w3.org/2000/09/xmldsig#", "ds");
// Registramos los Id de los elementos (Requerido en últimas versiones de Java)
signContext.setIdAttributeNS(soapBody, NAMESPACE_WSU, "Id");
signContext.setIdAttributeNS(nodoTimestamp, NAMESPACE_WSU, "Id");
KeyInfoFactory keyFactory = KeyInfoFactory.getInstance();
DOMStructure domKeyInfo = new DOMStructure(nodoSecurityTokenReference);
KeyInfo keyInfo = keyFactory.newKeyInfo(java.util.Collections.singletonList(domKeyInfo), id_key_info);
XMLSignature signature = xmlSignatureFactory.newXMLSignature(signedInfo, keyInfo);
signContext.setBaseURI("");
signature.sign(signContext);
} catch (Exception ex) {
CgnException cgnex = new CgnException(Errores.ERR_PROC_GENERAR_FIRMA_MENSAJE, ex);
throw cgnex;
}
}
我希望签名的 XML 与发送的 XML 相同,因此摘要值不会更改。
任何帮助将不胜感激。
几天后,我终于找到了问题所在。
为了签署正文,我必须为标签分配一个 ID,以及在 tar 下对这个 ID 的引用。
所以我的 XML 看起来像这样:
...
在此之后,我用我的私钥签署了传出消息。
这是我的 function 将 Id 属性添加到 Body 标签:
/**
* Asigna un identificador único al nodo Body del mensaje.
*
* @param soapMessage Mensaje SOAP
*
* @throws SOAPException
*/
private static void asignarIdNodoBody(SOAPMessage soapMessage) throws SOAPException {
String idBody = "Body-123456";
SOAPBody soapBody = soapMessage.getSOAPBody();
soapBody.setAttributeNS(NAMESPACE_WSU, "wsu:Id", id_body);
}
由于一些我不明白的奇怪原因,上面的代码导致添加的数字签名没有通过验证。
我用这个替换了上面的 function:
/**
* Asigna un identificador único al nodo Body del mensaje.
*
* @param soapMessage Mensaje SOAP
*
* @throws SOAPException
*/
private static void asignarIdNodoBody(SOAPMessage soapMessage) throws SOAPException {
String idBody = "Body-123456";
SOAPBody soapBody = soapMessage.getSOAPBody();
SOAPEnvelope soapEnvelope = soapMessage.getSOAPPart().getEnvelope();
Name name = soapEnvelope.createName("Id", "wsu", NAMESPACE_WSU);
soapBody.addAttribute(name, id_body);
}
瞧,我之后添加了数字签名。 现在它通过了验证。
Referencia [0]
URI: #Body-123456
Validacion OK: true
Digest: JMdmg+d/yJJA1wg7yzDctIBE9z4=
Expected digest: JMdmg+d/yJJA1wg7yzDctIBE9z4=
Referencia [1]
URI: #TS-1000
Validacion OK: true
Digest: sEY89etI7c+uGrFPh7W59nu/4ac=
Expected digest: sEY89etI7c+uGrFPh7W59nu/4ac=
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.