php-soap / psr18-wsse-middleware
为您的HTTP SOAP传输添加WSSE安全功能
Requires
- php: ~8.1.0 || ~8.2.0 || ~8.3.0
- ext-dom: *
- ext-openssl: *
- azjezz/psl: ^2.1
- paragonie/hidden-string: ^2.0
- php-http/client-common: ^2.3
- php-soap/engine: ^1.3|^2.0
- php-soap/psr18-transport: ^1.3
- php-soap/xml: ^1.4
- robrichards/wse-php: ^2.0
- veewee/xml: ^2.2||^3.0
Requires (Dev)
- cweagans/composer-patches: ^1.7
- nyholm/psr7: ^1.5
- php-http/mock-client: ^1.5
- phpunit/phpunit: ^9.5
- symfony/http-client: ^6.1
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) ] );
注意:加密也可以在不添加签名的情况下完成。