使用 PHP 生成 XML 签名摘要 [英] Generate an XML signature digest using PHP

查看:40
本文介绍了使用 PHP 生成 XML 签名摘要的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为我的 PHP SOAP 客户端实现 WS-Security.第一步是能够从传出请求生成有效的 XML 摘要,但我无法做到这一点.几天来我一直在寻找答案,但大多数答案最终都类似于不要自己解决,只需使用现有的 Java 库".这在我目前的情况下是不可行的.

I'm trying to implement WS-Security for my PHP SOAP client. The first step is being able to generate a valid XML digest from the outgoing request, but I haven't been able to do this. I've been looking for answers for a few days now but most of the answers end up being something like "don't solve it yourself, just use an existing Java library". That's not feasible in my current situation.

我一直在网上查看几个示例,试图重现它们所拥有的相同摘要,例如 这个来自微软.该页面列出了以下示例:

I have been looking at several examples on the net trying to reproduce the same digest they have, for example this one from Microsoft. That page lists the following example:

<ds:Object Id="ts-text">
    Wed Jun  4 12:11:06 EDT
</ds:Object>

然后他们显示预期的摘要值:

Then they show the expected digest value:

<ds:Reference URI="#ts-text">
    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
    <ds:DigestValue>pN3j2OeC0+/kCatpvy1dYfG1g68=</ds:DigestValue>
</ds:Reference>

这是我用来计算摘要值的代码:

This is the code I've been using to calculate the digest value:

<?php
$digest = base64_encode(hash('SHA1', $contents, true));

我尝试了许多不同的组合,包括删除空格或仅使用没有 XML 标记的时间戳,但都没有成功.我还尝试了更复杂的需要规范化的例子.这是我的单元测试之一:

I've tried many different combinations of removing whitespace or using just the timestamp with no XML tags with no success. I've also tried more complex examples where cannonicalization is needed. This is one of my unit tests:

public function testCreateDigest(DOMDocument $request, $expectedDigest) {

    $ns = $request->documentElement->namespaceURI;
    $body = $request
            ->getElementsByTagNameNS($ns, 'Body')
            ->item(0);

    $firstElement = '';
    foreach($body->childNodes as $node){
        if ($node->nodeType === XML_ELEMENT_NODE) {
            $firstElement = $node;
            break;
        }
    }


    $content = $firstElement->C14N(false, true);


    $actualDigest = base64_encode(hash('SHA1', $content, true));

    $this->assertEquals($expectedDigest, $actualDigest);

}

我到底应该散列什么?我错过了任何步骤吗?

What exactly am I supposed to hash? Am I missing any steps?

推荐答案

我找到了解决方案.对于我尝试的大多数示例,所需的转换是独占规范化和注释:http://www.w3.org/TR/2002/REC-xml-exc-c14n-20020718/#WithComments

I found the solution. For most of the examples I tried, the required transformation was exclusive canonicalization with comments: http://www.w3.org/TR/2002/REC-xml-exc-c14n-20020718/#WithComments

所以我的问题是我做错了转换.PHP 的 C14N 函数中的第一个参数定义了是否使用独占转换.代码应该是这样的(注意我去掉了对第一个元素的不必要的遍历):

So my problem was that I was doing the transformation wrong. The first parameter in PHP's C14N function defines whether to use exclusive transformation or not. This is what the code should have been (note that I removed the unnecessary traversal to the first element):

public function testCreateDigest(DOMDocument $request, $expectedDigest) {

    $ns = $request->documentElement->namespaceURI;
    $body = $request
        ->getElementsByTagNameNS($ns, 'Body')
        ->item(0);

    $content = $body->C14N(true, true); // <-- exclusive, with comments

    $actualDigest = base64_encode(hash('SHA1', $content, true));

    $this->assertEquals($expectedDigest, $actualDigest);

}

所以你有它.这提醒我在漫无目的地编码之前仔细检查我的 XML 并了解标准.

So there you have it. This served as a reminder for me to double check my XML and understand the standards before I go coding aimlessly.

这篇关于使用 PHP 生成 XML 签名摘要的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆