如何在 ssl:// 传输的 PHP 流上下文中强制使用某个 TLS 版本?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16547163/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to force a certain TLS version in a PHP stream context for the ssl:// transport?
提问by Chriki
How can I force TLSv1.0 in a PHP stream context when trying to access an https
URL?
尝试访问https
URL时,如何在 PHP 流上下文中强制使用 TLSv1.0 ?
I'm looking for something along the lines of this:
我正在寻找类似这样的东西:
$context = stream_context_create(
array(
'ssl' => array(
'protocol_version' => 'tls1',
),
));
file_get_contents('https://example.com/test', false, $context);
Background
背景
Actually I'm facing an issue in Ubuntu 12.04when working with PHP's SoapClient
. Unfortunately, the server I'm trying to connect to does only support SSLv3.0/TLSv1.0 and fails on the default TLSv1.1 negotiation. Therefore I'd like to explicitly set the protocol of the ssl://
transport to TLSv1.0.
实际上,我在 Ubuntu 12.04 中使用 PHP 的SoapClient
. 不幸的是,我尝试连接的服务器仅支持 SSLv3.0/TLSv1.0,并且在默认的 TLSv1.1 协商中失败。因此,我想将ssl://
传输协议明确设置为 TLSv1.0。
回答by phil-lavin
PHP 5.6+ Users
PHP 5.6+ 用户
This is a new feature as documented on the PHP 5.6 OpenSSL Changes page.
这是PHP 5.6 OpenSSL Changes page 中记录的新功能。
At time of writing this, PHP5.6 is in Beta1 and thus this isn't overly useful. People of the future - lucky you!
在撰写本文时,PHP5.6 处于 Beta1 中,因此这不是很有用。未来的人 - 幸运的你!
The future is upon us. PHP 5.6 is a thing and its use should be encouraged. Be aware that it deprecates some fairly widely used things like mysql_* functions so care should be taken when upgrading.
未来就在我们身上。PHP 5.6 是一个东西,应该鼓励使用它。请注意,它弃用了一些相当广泛使用的东西,例如 mysql_* 函数,因此升级时应小心。
Everyone else
其他所有人
@toubsen is correct in his answer - this isn't directly possible. To elaborate on his suggested workarounds... when working around a problem where a supplier's API server wasn't correctly negotiating TLSv1.2 down to its supported TLSv1.0, sending a small subset of ciphers seemed to allow negotiation to complete correctly. Stream context code is:
@toubsen 在他的回答中是正确的 - 这不是直接可能的。详细说明他建议的解决方法......在解决供应商的 API 服务器未正确协商 TLSv1.2 到其支持的 TLSv1.0 的问题时,发送一小部分密码似乎允许协商正确完成。流上下文代码是:
$context = stream_context_create(
[
'ssl' => [
'ciphers' => 'DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:AES256-SHA:KRB5-DES-CBC3-MD5:KRB5-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:EDH-DSS-DES-CBC3-SHA:DES-CBC3-SHA:DES-CBC3-MD5:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:AES128-SHA:RC2-CBC-MD5:KRB5-RC4-MD5:KRB5-RC4-SHA:RC4-SHA:RC4-MD5:RC4-MD5:KRB5-DES-CBC-MD5:KRB5-DES-CBC-SHA:EDH-RSA-DES-CBC-SHA:EDH-DSS-DES-CBC-SHA:DES-CBC-SHA:DES-CBC-MD5:EXP-KRB5-RC2-CBC-MD5:EXP-KRB5-DES-CBC-MD5:EXP-KRB5-RC2-CBC-SHA:EXP-KRB5-DES-CBC-SHA:EXP-EDH-RSA-DES-CBC-SHA:EXP-EDH-DSS-DES-CBC-SHA:EXP-DES-CBC-SHA:EXP-RC2-CBC-MD5:EXP-RC2-CBC-MD5:EXP-KRB5-RC4-MD5:EXP-KRB5-RC4-SHA:EXP-RC4-MD5:EXP-RC4-MD5',
],
]
);
SOAP Users
SOAP 用户
PHP's SOAP client doesn't use curl, nor does it seem to use the default context set with stream_context_set_default
. As such, the created context needs to be passed to the SOAPClient constructor in the 2nd parameter as such:
PHP 的 SOAP 客户端不使用 curl,它似乎也不使用设置的默认上下文stream_context_set_default
。因此,创建的上下文需要传递给第二个参数中的 SOAPClient 构造函数,如下所示:
$soap_client = new SOAPClient('http://webservices.site.com/wsdlfile.wsdl', array('stream_context' => $context));
Why those Ciphers?
为什么是那些密码?
Running the command openssl ciphers
on the server gives you a list of supported ciphers in the above format. Running openssl ciphers -v
tells you those that are TLSv1.2 specific. The above list was compiled from all of the non-TLSv1.2 ciphers reported by OpenSSL.
openssl ciphers
在服务器上运行该命令将为您提供上述格式的受支持密码列表。运行会openssl ciphers -v
告诉您那些特定于 TLSv1.2 的内容。上面的列表是从 OpenSSL 报告的所有非 TLSv1.2 密码编译而来的。
openssl ciphers -v | grep -v 'TLSv1.2' | cut -d ' ' -f 1 | tr "\n" ':'
openssl ciphers -v | grep -v 'TLSv1.2' | cut -d ' ' -f 1 | tr "\n" ':'
回答by Robert McMahan
In case someone wants to know how to "disable" TLSv1.0 when making a SOAP request...
如果有人想知道如何在发出 SOAP 请求时“禁用”TLSv1.0...
$parameters = array(
'trace' => true,
'exceptions' => true,
'cache_wsdl' => WSDL_CACHE_NONE,
'stream_context' => stream_context_create(array(
'ssl' => array(
'ciphers' => 'DEFAULT:!TLSv1.0:!SSLv3'
),
)),
'connection_timeout' => 15
);
$client = new SoapClient(YOUR_WSDL_URL_HERE, $parameters);
The key part here is that stream context ciphersline. This says use the default ciphers, but exclude TLSv1.0 ciphers (the 1.0 package also has TLSv1.1 ciphers). The : is the cipher package separator (what goes between packages) and the ! here is to tell it to exclude this package (it's a hard exclude so if it shows up later in the list it will still be excluded). Soft exclude is - character and add to the end of the list is + character. To add in order just add it without anything in front of it.
这里的关键部分是流上下文密码行。这表示使用默认密码,但排除 TLSv1.0 密码(1.0 包也有 TLSv1.1 密码)。: 是密码包分隔符(包之间的内容)和 ! 这是告诉它排除这个包(这是一个硬排除,所以如果它稍后出现在列表中,它仍然会被排除)。软排除是 - 字符并添加到列表末尾是 + 字符。要按顺序添加,只需在其前面添加任何内容即可。
Cipher information here: https://www.openssl.org/docs/manmaster/man1/ciphers.html#CIPHER-LIST-FORMAT
这里的密码信息:https: //www.openssl.org/docs/manmaster/man1/ciphers.html#CIPHER-LIST-FORMAT
Edit: For whatever reason including the
编辑:无论出于何种原因,包括
'ssl_method' => SOAP_SSL_METHOD_TLS,
part from the options was really causing me headaches and wouldn't connect in certain contexts. After tons of troubleshooting and playing around with options I finally realized that removing this setting and letting it autoset this seems to have resolved the issue.
选项中的一部分确实让我头疼,并且在某些情况下无法连接。经过大量的故障排除和各种选项后,我终于意识到删除此设置并让它自动设置似乎已经解决了问题。
回答by toubsen
Base information
基本信息
The field protocol_version
is only valid for HTTP context (HTTP 1.0 vs 1.1), but does not affect the SSL context.
该字段protocol_version
仅对 HTTP 上下文(HTTP 1.0 与 1.1)有效,但不影响 SSL 上下文。
The following manual page lists all stream context options for PHP: Context options and parameters
以下手册页列出了 PHP 的所有流上下文选项: 上下文选项和参数
For all SSL based stream wrappers, only the follwing options are available: SSL context options
对于所有基于 SSL 的流包装器,只有以下选项可用: SSL 上下文选项
Possible solutions / workarounds
可能的解决方案/变通方法
First advice: Get the server admin to fix his server instead of working around this in your client ;-)
第一个建议:让服务器管理员修复他的服务器,而不是在您的客户端中解决这个问题;-)
Maybe you can get it wo work with the ciphers
optionfor SSL streams, to pass only one exact TLSv1.0 cipher suite(that is unique to TLSv1.0) in the list, that your target server supports.
也许您可以使用SSL 流ciphers
选项使其仅传递目标服务器支持的列表中的一个精确的TLSv1.0 密码套件(TLSv1.0 独有)。
Switching the implementaion to use cURL will most probaly also not help here, as according to an entry in their mailing list, there's no option to force a certain TLS version - the client will downgrade when needed automatically.
将实现切换为使用 cURL 在这里很可能也无济于事,因为根据他们邮件列表中的条目,没有选项可以强制使用某个 TLS 版本 - 客户端将在需要时自动降级。
tl;dr
tl;博士
I currently know of no way to explicitly force TLSv1.0 for SSL connections from PHP.
我目前不知道有什么方法可以明确强制 TLSv1.0 用于来自 PHP 的 SSL 连接。
回答by Arun Vasudevan Nair
I can confirm that above accepted answer does not work for Ubuntu 12.04 and PHP 5.4.33 combination. Also found out that I have to manually specify certificate when trying openssl and curl to access https endpoints. I ended up using RHEL 7 and PHP 5.5 to achieve a solid solution as I was developing integration for an enterprise application. Nothing against Ubuntu, but in my specific case it didn't work.
我可以确认上述接受的答案不适用于 Ubuntu 12.04 和 PHP 5.4.33 组合。还发现我在尝试 openssl 和 curl 访问 https 端点时必须手动指定证书。我最终使用 RHEL 7 和 PHP 5.5 来实现可靠的解决方案,因为我正在为企业应用程序开发集成。对 Ubuntu 没有任何影响,但在我的特定情况下它不起作用。