如何让PHP SOAP客户端与运行在SSL上并且具有无效证书的服务进行通信

4

我正在尝试使用PHP SOAP客户端来消费一个SOAP服务,但是它失败并显示以下错误信息:

SoapFault: SOAP-ERROR: Parsing WSDL: Couldn't load from 'https://domain.com/webservice.asmx?wsdl' : failed to load external entity "https://domain.com/webservice.asmx?wsdl"\n in /Users/andrewdchancox/Projects/test/testsoap.php on line 10

我已经下载了wsdl文件,并从本地的apache实例中提供服务,它可以顺利加载。唯一能想到的问题是Web服务在SSL上运行,使用自签名证书-当我使用wget下载wsdl时,会出现以下错误:

--2012-09-11 16:28:39--
https://domain.com/webservice.asmx?wsdl
Resolving domain.com (domain.com)... 11.111.111.11
Connecting to domain.com (domain.com)|11.111.111.11|:443... connected.
ERROR: The certificate of ‘domain.com’ is not trusted.
ERROR: The certificate of ‘domain.com’ hasn't got a known issuer.

我已经谷歌搜索并仔细阅读了PHP SOAP客户端 - http://php.net/manual/en/class.soapclient.php和它的构造函数 - http://www.php.net/manual/en/soapclient.soapclient.php,但没有找到任何有助于解决问题的信息。
大家有什么想法吗?

可能是PHP SOAP无法连接到SSL WSDL源的重复问题。 - Mike Brant
那个问题很久以前就解决了 - 今天我一直在使用另一个在同一开发环境下运行的基于SSL的SOAP服务,一切都正常工作。 - Andrew Hancox
@AndrewHancox:你是怎么解决这个问题的?我也遇到了同样的问题。 - HeinrichStack
1个回答

6

这是两年前的内容,但我认为它值得回答。

PHP中的SoapClient类使用PHP流来进行HTTP通信。由于各种原因,通过PHP流进行的SSL不安全1,但在这种情况下,您的问题是它太安全了。

解决方案的第一步是在构建SoapClient2时使用stream_context选项。这将允许您指定更高级的SSL设置3

// Taken from note 1 below.
$contextOptions = array(
    'ssl' => array(
        'verify_peer'   => true,
        'cafile'        => '/etc/ssl/certs/ca-certificates.crt',
        'verify_depth'  => 5,
        'CN_match'      => 'api.twitter.com',
        'disable_compression' => true,
        'SNI_enabled'         => true,
        'ciphers'             => 'ALL!EXPORT!EXPORT40!EXPORT56!aNULL!LOW!RC4'
    )
);
$sslContext = stream_context_create($contextOptions);
// Then use this context when creating your SoapClient.
$soap = new SoapClient('https://domain.com/webservice.asmx?wsdl', array('stream_context' => $sslContext));

您的问题的理想解决方案是创建自己的CA证书,使用该证书签署SSL证书,并将您的CA证书添加到cafile中。更好的方法可能是仅在cafile中拥有该证书,以避免一些流氓CA为您的域签署其他人的证书,但这并不总是实用的。
如果您所做的事情不需要安全性(例如在测试期间),您还可以使用流上下文中的SSL设置来降低连接的安全性。选项allow_self_signed将允许使用自签名证书:
$contextOptions = array(
    'ssl' => array(
        'allow_self_signed' => true,
    )
);
$sslContext = stream_context_create($contextOptions);
$soap = new SoapClient('https://domain.com/webservice.asmx?wsdl', array('stream_context' => $sslContext));

链接:

  1. 《深入 PHP 安全》——传输层安全性(HTTPS、SSL 和 TLS)——PHP 流
  2. PHP:SoapClient::SoapClient
  3. PHP:SSL 上下文选项

感谢您的回答,即使是两年后 - 这篇文章也是唯一让我度过了几天头痛的事情(具体来说,是在调用SoapClient构造函数之外创建流上下文,并指向cafile)。 - Rob G

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接