我正在使用xmlseclibs来尝试签署一个SOAP文档,但它似乎不会以相同的方式规范事物,具体取决于我是签名还是验证。
我会举个例子。这是我试图签署的XML:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" MajorVersion="1" MinorVersion="1" IssueInstant="2010-02-04T15:27:43Z" ResponseID="pfxe85313e6-e688-299a-df06-30f55e24f65a">
<samlp:Status>
<samlp:StatusCode Value="samlp:Requester"/>
</samlp:Status>
</samlp:Response>
</soapenv:Body>
</soapenv:Envelope>
我使用PHP编写了一些代码,使用公钥和私钥证书的组合对其进行签名,它似乎有效。它添加了<ds:Signature>
元素以及所有适当的东西,它看起来很棒。但后来我通过在签名后立即尝试验证它来测试它,再次使用xmlseclibs(和公钥证书),但验证失败。所以完全相同的代码库正在进行签名和验证,但这两个过程由于某种原因不同意。
我向xmlseclibs添加了一些调试代码,以了解它正在做什么,我意识到它出现的签名密钥和它提出的验证密钥的原因是不同的,因为它在两种情况下以不同的方式规范化。当我告诉它签署<samlp:Response>
元素时,这是它标记的规范形式(为了便于阅读,我在这里添加了新行):
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" IssueInstant="2010-02-04T15:27:43Z" MajorVersion="1" MinorVersion="1" ResponseID="pfxe85313e6-e688-299a-df06-30f55e24f65a" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion">
<samlp:Status>
<samlp:StatusCode Value="samlp:Requester">
</samlp:StatusCode>
</samlp:Status>
</samlp:Response>
然而,当它验证签名时,这是它计算验证的规范形式(再次,我在这里添加了新行):
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" IssueInstant="2010-02-04T15:27:43Z" MajorVersion="1" MinorVersion="1" ResponseID="pfxe85313e6-e688-299a-df06-30f55e24f65a">
<samlp:Status>
<samlp:StatusCode Value="samlp:Requester">
</samlp:StatusCode>
</samlp:Status>
</samlp:Response>
正如您所看到的,此版本省略了xmlns:saml
元素中的<samlp:Response>
属性,而第一个则没有。 (请注意,这与xmlns:samlp
属性不同,后者包含在两者中。)这看起来非常像xmlseclibs中的错误,但是如果我只是知道哪个规范,那么我很乐意修复自己形式是正确的。独占规范化是否应该省略该属性?还是应该包括在内?哪一个是正确的独家规范形式?
答案 0 :(得分:3)
两者都不是正确的规范形式!
签名XML在非命名空间属性之后有一个名称空间声明,它违反了文档顺序规则:
命名空间节点的文档顺序位置比属性节点小。
验证XML完全缺少saml
命名空间节点。 Canonicalisation不会仅仅因为没有引用它们的子内容而删除命名空间节点。它只删除冗余的命名空间节点(即已经在父节点上生效的命名空间)。
我对xmlseclibs的了解不足以说明为什么会发生这种情况,但这两方面都是错误的。 FWIW我的DOM上的c14n函数在这里说:
<samlp:Response xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" IssueInstant="2010-02-04T15:27:43Z" MajorVersion="1" MinorVersion="1" ResponseID="pfxe85313e6-e688-299a-df06-30f55e24f65a">
<samlp:Status>
<samlp:StatusCode Value="samlp:Requester"></samlp:StatusCode>
</samlp:Status>
</samlp:Response>
eta:我刚看了SVN中的xmlseclibs.php
,并没有一个简单的解决办法,因为它目前的方法存在根本缺陷。它尝试创建一个“规范化的”DOM,然后使用普通的saveXML()
将其序列化。由于存在关于saveXML
不承诺遵循的属性顺序和字符转义的C14N序列化规则,因此无法实现这一点。
答案 1 :(得分:2)
您正在不正确地创建DOM文档并尝试使用无效的内存中树。在尝试签名之前,序列化并使用序列化结果或在树中正确创建名称空间声明。有关详细信息,请参阅错误报告:http://code.google.com/p/xmlseclibs/issues/detail?id=6