php-soap/psr18-wsse-middleware

为您的HTTP SOAP传输添加WSSE安全功能

2.4.0 2024-04-29 10:59 UTC

This package is auto-updated.

Last update: 2024-08-29 11:40:59 UTC


README

此包提供了您添加WSSE和WSA安全到基于PSR-18的SOAP传输所需的工具。

想帮忙?💚

想了解更多关于此项目未来的信息?查看我们将要工作的下一个大型项目列表。

安装

composer require php-soap/psr18-wsse-middleware

此包包含php-soap/psr18-transport 包,并旨在与其一起使用。它是robrichards的wse-php包的中间件包装器。

使用方法

WsaMiddleware

如果您的远程服务器期望请求中存在Web服务地址(WSA)头,则可以激活此中间件。中间件是一个轻量级的包装器,易于在应用程序中使用。

如果您需要基于WSA w3c 2005的Web服务地址,则应使用WsaMiddleware2005。

use Http\Client\Common\PluginClient;
use Soap\Psr18Transport\Psr18Transport;
use Soap\Psr18WsseMiddleware\WsaMiddleware;
use Soap\Psr18WsseMiddleware\WsaMiddleware2005;

$transport = Psr18Transport::createForClient(
    new PluginClient($yourPsr18Client, [
        new WsaMiddleware(),
        // OR
        new WsaMiddleware2005(),
    ])
);

WsseMiddleware

哎呀 ... WS-Security ... 真是个麻烦!此包旨在尽可能灵活,并提供您正确配置Web服务安全所需的工具。组件基于SoapUI中的WS-Security UI设计。这使您能够按照SOAP服务器的要求配置一切!如果您在SoapUI上有有效的配置,可以通过遵循条目及其配置将其转换为PHP代码。

使用方法

use Http\Client\Common\PluginClient;
use Soap\Psr18Transport\Psr18Transport;
use Soap\Psr18WsseMiddleware\WsseMiddleware;

$transport = Psr18Transport::createForClient(
    new PluginClient($yourPsr18Client, [
        new WsseMiddleware([$entries])
    ])
);

WSSE中间件可以由多个可配置的条目构建

  • BinarySecurityToken
  • 解密
  • 加密
  • SamlAssertion
  • 签名
  • 时间戳
  • 用户名

以下是一些配置$wsseMiddleware的常见示例。

添加用户名和密码

某些服务要求您添加用户名,可选地添加密码。这可以通过以下中间件完成。

use Soap\Psr18WsseMiddleware\WsseMiddleware;
use Soap\Psr18WsseMiddleware\WSSecurity\Entry;

$wsseMiddleware = new WsseMiddleware(
    outgoing: [
        (new Entry\Username($user))
            ->withPassword('xxx')
            ->withDigest(false),
    ]
);

密钥存储

此包提供了一些Key包装器,可用于传递私钥/公钥

  • KeyStore\Certificate: 包含PEM格式的公共X.509证书。
  • KeyStore\Key: 包含PKCS_8格式的私钥。
  • KeyStore\ClientCertificate: 包含PEM格式的公共X.509证书和PKCS_8私钥。

示例

use Soap\Psr18WsseMiddleware\WSSecurity\KeyStore\Certificate;
use Soap\Psr18WsseMiddleware\WSSecurity\KeyStore\ClientCertificate;
use Soap\Psr18WsseMiddleware\WSSecurity\KeyStore\Key;

$privKey = Key::fromFile('security_token.priv')->withPassphrase('xxx'); // Regular private key (not wrapped in X509)
$pubKey = Certificate::fromFile('security_token.pub'); // Public X509 cert

// or:

$bundle = ClientCertificate::fromFile('client-certificate.pem')->withPassphrase('xxx');
$privKey = $bunlde->privateKey();
$pubKey = $bunlde->publicCertificate();

在p12证书的情况下:首先将其转换为私钥和公共X509证书

openssl pkcs12 -in your.p12 -out security_token.pub -clcerts -nokeys
openssl pkcs12 -in your.p12 -out security_token.priv -nocerts -nodes

使用PKCS12或X509证书对SOAP请求进行签名。

这是WSS中最常见的实现之一。您从肥皂服务中获得的证书,您需要用它来获取数据。

接下来,您可以按以下方式配置中间件

use Soap\Psr18WsseMiddleware\WSSecurity\KeyStore\Certificate;
use Soap\Psr18WsseMiddleware\WSSecurity\KeyStore\Key;
use Soap\Psr18WsseMiddleware\WSSecurity\SignatureMethod;
use Soap\Psr18WsseMiddleware\WSSecurity\DigestMethod;
use Soap\Psr18WsseMiddleware\WSSecurity\KeyIdentifier;
use Soap\Psr18WsseMiddleware\WsseMiddleware;
use Soap\Psr18WsseMiddleware\WSSecurity\Entry;

$privKey = Key::fromFile('security_token.priv')->withPassphrase('xxx');
$pubKey = Certificate::fromFile('security_token.pub');

$wsseMiddleware = new WsseMiddleware(
    outgoing: [
        new Entry\Timestamp(60),
        new Entry\BinarySecurityToken($pubKey),
        (new Entry\Signature(
            $privKey,
            new KeyIdentifier\BinarySecurityTokenIdentifier()
        ))
            ->withSignatureMethod(SignatureMethod::RSA_SHA256)
            ->withDigestMethod(DigestMethod::SHA256)
            ->withSignAllHeaders(true)
            ->withSignBody(true)
    ]
);

此示例还可以与签名和用户身份验证一起使用。

使用SAML断言授权SOAP请求

另一种常见的实现是通过符合WS-Trust的STS实例进行身份验证。在这种情况下,您首先需要从STS服务获取SAML断言。大多数都要求您使用X509证书对请求进行签名。这可以通过上面的中间件完成。

一旦收到您的SAML断言,您必须将其传递给想要联系的服务。传递SAML断言的常见配置可能如下所示

use Soap\Psr18WsseMiddleware\WSSecurity\KeyStore\Certificate;
use Soap\Psr18WsseMiddleware\WSSecurity\KeyStore\Key;
use Soap\Psr18WsseMiddleware\WSSecurity\SignatureMethod;
use Soap\Psr18WsseMiddleware\WSSecurity\DigestMethod;
use Soap\Psr18WsseMiddleware\WSSecurity\KeyIdentifier;
use Soap\Psr18WsseMiddleware\WsseMiddleware;
use Soap\Psr18WsseMiddleware\WSSecurity\Entry;
use VeeWee\Xml\Dom\Document;
use function VeeWee\Xml\Dom\Locator\document_element;

$privKey = Key::fromFile('security_token.priv')->withPassphrase('xxx');

// These are provided through the STS service.
$samlAssertion = Document::fromXmlString(<<<EOXML
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" AssertionID="xxxx" />
EOXML
);
$samlAssertionId = $samlAssertion->locate(document_element())->getAttribute('AssertionID');

$wsseMiddleware = new WsseMiddleware(
    outgoing: [
        new Entry\Timestamp(60),
        (new Entry\Signature(
            $privKey,
            new KeyIdentifier\SamlKeyIdentifier($samlAssertionId)
        ))
            ->withSignatureMethod(SignatureMethod::RSA_SHA256)
            ->withDigestMethod(DigestMethod::SHA256)
            ->withSignAllHeaders(true)
            ->withSignBody(true)
            ->withInsertBefore(false),
        new Entry\SamlAssertion($samlAssertion),
    ]
);

加密敏感数据

某些服务要求您加密请求中的敏感部分以及响应中的敏感部分。在这种情况下,您可以将您的公钥添加到请求中,加密负载并发送。入站响应将使用您的公钥加密,并可以使用您的私钥解密。

加密包含一个已知错误,该错误位于底层robrichards/wse-php库中。由于修复尚未合并,您可以应用如下补丁

composer require --dev cweagans/composer-patches
{
  "extra": {
    "patches": {
      "robrichards/wse-php": {
        "Fix encryption bug": "https://patch-diff.githubusercontent.com/raw/robrichards/wse-php/pull/67.diff"
      }
    }
  }
}

加密的配置如下所示

use Soap\Psr18WsseMiddleware\WSSecurity\DataEncryptionMethod;
use Soap\Psr18WsseMiddleware\WSSecurity\KeyEncryptionMethod;
use Soap\Psr18WsseMiddleware\WSSecurity\KeyStore\Certificate;
use Soap\Psr18WsseMiddleware\WSSecurity\KeyStore\Key;
use Soap\Psr18WsseMiddleware\WSSecurity\SignatureMethod;
use Soap\Psr18WsseMiddleware\WSSecurity\DigestMethod;
use Soap\Psr18WsseMiddleware\WSSecurity\KeyIdentifier;
use Soap\Psr18WsseMiddleware\WsseMiddleware;
use Soap\Psr18WsseMiddleware\WSSecurity\Entry;

$privKey = Key::fromFile('security_token.priv')->withPassphrase('xxx'); // Private key
$pubKey = Certificate::fromFile('security_token.pub'); // Public X509 cert
$signKey = Certificate::fromFile('sign-key.pem'); // X509 cert for signing. Could be the same as $pubKey.

$wsseMiddleware = new WsseMiddleware(
    outgoing: [
        new Entry\Timestamp(60),
        new Entry\BinarySecurityToken($pubKey),
        (new Entry\Signature(
            $privKey,
            new KeyIdentifier\BinarySecurityTokenIdentifier()
        ))
        (new Entry\Encryption(
            $signKey,
            new KeyIdentifier\X509SubjectKeyIdentifier($signKey)
        ))
            ->withKeyEncryptionMethod(KeyEncryptionMethod::RSA_OAEP_MGF1P)
            ->withDataEncryptionMethod(DataEncryptionMethod::AES256_CBC)
    ],
    incoming: [
        new Entry\Decryption($privKey)
    ]
);

注意:加密也可以在不添加签名的情况下完成。