我开发的API客户端使用XML消息,消息根据XML Signature Syntax and Processing规范进行签名。经过长时间的斗争,我终于得到了签名。
此时我正在使用HEREDOC(简单的php字符串)构建XML并进行清理,我想直接使用DOMDocument创建XML。但是,这会导致服务器使消息失效。
这是当前的设置(签名后服务器接受此消息):
$xml = <<<EOT
<?xml version="1.0" encoding="UTF-8"?>
<DirectoryReq xmlns="http://www.idealdesk.com/ideal/messages/mer-acq/3.3.1" version="3.3.1">
<createDateTimestamp>$timestamp</createDateTimestamp>
<Merchant>
<merchantID>$merchantId</merchantID>
<subID>$subId</subID>
</Merchant>
</DirectoryReq>
EOT;
$document = new DOMDocument();
$document->loadXML($xml);
这是OO方法(签名时服务器拒绝此消息):
$document = new DOMDocument('1.0', 'UTF-8');
$request = $document->createElement('DirectoryReq');
$xmlns = $document->createAttribute('xmlns');
$xmlns->value = 'http://www.idealdesk.com/ideal/messages/mer-acq/3.3.1';
$version = $document->createAttribute('version');
$version->value = '3.3.1';
$request->appendChild($xmlns);
$request->appendChild($version);
$merchant = $document->createElement('Merchant');
$merchant->appendChild($document->createElement('merchantID', $merchantId));
$merchant->appendChild($document->createElement('subID', $subId));
$request->appendChild($document->createElement('createDateTimestamp', $timestamp));
$request->appendChild($merchant);
$document->appendChild($request);
什么可能导致差异,因为XML签名被服务器无效?签名消息的代码完全相同。服务器只是报告“电子签名无效”。
如果需要,我可以显示更多代码。
编辑,生成XML的更多输出和比较
为了提供更多信息,这是第一个(HEREDOC)xml的输出,通过$document->saveXml()
生成:
<?xml version="1.0" encoding="UTF-8"?>
<DirectoryReq xmlns="http://www.idealdesk.com/ideal/messages/mer-acq/3.3.1" version="3.3.1">
<createDateTimestamp>2013-08-10T19:41:20.000Z</createDateTimestamp>
<Merchant>
<merchantID>0020XXXXXX</merchantID>
<subID>0</subID>
</Merchant>
</DirectoryReq>
这是第二个(直接DOMDocument生成)方法的输出($document->saveXML()
):
<?xml version="1.0" encoding="UTF-8"?>
<DirectoryReq xmlns="http://www.idealdesk.com/ideal/messages/mer-acq/3.3.1" version="3.3.1">
<createDateTimestamp>2013-08-10T19:41:20.000Z</createDateTimestamp>
<Merchant>
<merchantID>0020XXXXXX</merchantID>
<subID>0</subID>
</Merchant>
</DirectoryReq>
在php中,var_dump()
给出完全相同的字符串长度。如果我比较两个字符串(显然===
)它们是相同的。比较两个对象,它们不相同。
签名示例
使用此代码使用库xmlseclibs进行签名(注意。两种类型都以相同的方式签名!):
public function sign(DOMDocument $document, $fingerprint, $keyfile, $passphrase = null)
{
$dsig = new XMLSecurityDSig();
$dsig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);
$dsig->addReference($document, XMLSecurityDSig::SHA256,
array('http://www.w3.org/2000/09/xmldsig#enveloped-signature'),
array('force_uri' => true)
);
$key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, array('type' => 'private'));
if ($passphrase !== null) {
$key->passphrase = $passphrase;
}
$key->loadKey($keyfile, true);
$dsig->sign($key);
$dsig->addKeyInfoAndName($fingerprint);
$dsig->appendSignature($document->documentElement);
}
如果我在签名后转储XML,则<DigestValue>
和<SignatureValue>
值会有所不同。所以服务器 是正确的,签名是无效的,但我无法想出方法A的工作原理和B的工作原理。
答案 0 :(得分:0)
您在创建$merchant
元素时覆盖Merchant
,因此只需重命名变量
$merchantElement = $document->createElement('Merchant');
答案 1 :(得分:0)
我现在通过再次导出和导入XML来解决它。它非常难看,但允许我灵活地处理DOMNodes。
protected function repairDOMDocument(DOMDocument $document)
{
$xml = $document->saveXML();
$document = new DOMDocument;
$document->loadXML($xml);
return $document;
}
如果有人建议如何停止这样做,我很高兴听到这样的话。