Checking signature in WS* server implementation

2019-06-19 05:48发布

问题:

I want to verify a signature for a soap request on a soap server implemented in php.

The server code:

$Server = new SoapServer();

$d = new DOMDocument();
$d->load('php://input');

$s = new WSSESoapServer($d);
try {
    if($s->process()) {
        // Valid signature
        $Server->handle($s->saveXML());
    } else {
        throw new Exception('Invalid signature');
    }
} catch (Exception $e) {
    echo "server exception: " . $e;
}

The error:

exception 'Exception' with message 'Error loading key to handle Signature' in /<path>/wse/src/WSSESoapServer.php:146

I have implemented a Client to sign SOAP requests using this library: https://github.com/robrichards/wse-php. There are no examples of how to implement the server...

How do I load the public key to check the signature?

[Edit] I have now been able to load the supplied key using

    $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public'));
    $key->loadKey(CERT, true);

I am no longer getting an error message when validating the signature:

$x = new XMLSecurityDSig();
$d = $x->locateSignature($soapDoc);
$valid = $x->verify($key);

However, $valid is always false. I have no idea if it's because the key is loaded wrong or is actually invalid. I can find very little information on implementing a SOAP server with PHP and no information on implementing a SOAP server that relies on checking a signed request.

CLARIFICATION

  1. My client talks to a remote web service and gets an acknowledgement.

  2. Then the remote server takes some time to process my request.

  3. A remote client (that I have no control over) then makes a request to my service.

The last step is where I have trouble verifying the signature

回答1:

Well anyways, your first approach looks fine to me, my server has the same structure. Unfortunately, WSSESoapServer does not inherit from SoapServer, thus is not really an SoapServer, but rather a SoapSignatureValidator and should be called like that. It would be easily possible to correct that behaviour, that one would not need a separate SoapServer instance (should be transparent and automatically).

<?php
require 'soap-server-wsse.php';

try {
    // get soap message
    $xmlSoap = DOMDocument::load('php://input');

    // validate signature
    $validateSignature = new WSSESoapServer($xmlSoap);
    if(!$validateSignature->process())
        file_put_contents("log.txt", "soapserver: SIGNATURE VALIDATION ERROR - CONTINUING WITHOUT SIGNATURE\n", FILE_APPEND);
        //throw new Exception('Invalid Signature'); # this would cancel the execution and not send an answer

    $sServer = new SoapServer($wsdl);
    // actually process the soap message and create & send answer
    //$sServer->setClass() or setObject() or set setFunction()
    $sServer->handle($validateSignature->saveXML());
} catch (Exception $fault) {
    file_put_contents("log.txt", "soapserver soapfault: ".print_r($fault, true), FILE_APPEND);
}
?>