如何在ssl:// transport的PHP流上下文中强制某个TLS版本?

时间:2013-05-14 15:27:13

标签: php ssl

在尝试访问https网址时,如何在PHP流上下文中强制使用TLSv1.0?

我正在寻找类似的东西:

$context = stream_context_create(
  array(
    'ssl' => array(
      'protocol_version' => 'tls1',
    ),
  ));
file_get_contents('https://example.com/test', false, $context);

背景

实际上,在使用PHP的an issue in Ubuntu 12.04时,我正面临SoapClient。不幸的是,我正在尝试连接的服务器仅支持SSLv3.0 / TLSv1.0,并且在默认的TLSv1.1协商时失败。因此,我想明确将ssl://传输的协议设置为TLSv1.0。

4 个答案:

答案 0 :(得分:13)

PHP 5.6+用户

这是PHP 5.6 OpenSSL Changes page中记录的新功能。

在撰写本文时,PHP5.6在Beta1中,因此它并不过分有用。未来的人 - 幸运的你!

未来在我们身上。 PHP 5.6是一个东西,应该鼓励它的使用。请注意,它会弃用一些相当广泛使用的东西,比如mysql_ *函数,所以在升级时应该小心。

其他人

@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用户

PHP的SOAP客户端不使用curl,似乎也没有使用stream_context_set_default设置的默认上下文。因此,创建的上下文需要在第二个参数中传递给SOAPClient构造函数:

$soap_client = new SOAPClient('http://webservices.site.com/wsdlfile.wsdl', array('stream_context' => $context));

为什么是那些密码?

在服务器上运行命令openssl ciphers,可以获得上述格式的受支持密码列表。运行openssl ciphers -v会告诉您特定于TLSv1.2的那些。上面的列表是从OpenSSL报告的所有非TLSv1.2密码编译而来的。

openssl ciphers -v | grep -v 'TLSv1.2' | cut -d ' ' -f 1 | tr "\n" ':'

答案 1 :(得分:3)

如果有人想知道如何"禁用"发出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);

这里的关键部分是流上下文密码行。这表示使用默认密码,但不包括TLSv1.0密码(1.0软件包也有TLSv1.1密码)。 :是密码包分隔符(包之间的东西)和!这是告诉它要排除这个包(它是一个很难排除的,所以如果它稍后出现在列表中,它仍将被排除)。软排除是 - 字符并添加到列表的末尾是+字符。要按顺序添加,只需在其前面添加任何内容即可添加。

此处的密码信息:https://www.openssl.org/docs/manmaster/man1/ciphers.html#CIPHER-LIST-FORMAT

编辑: 无论出于何种原因,包括

'ssl_method' => SOAP_SSL_METHOD_TLS,
选项的一部分确实让我感到头痛,并且在某些情况下不会连接。经过大量的故障排除和解决方案后,我终于意识到删除此设置并让它自动设置这似乎解决了这个问题。

答案 2 :(得分:1)

基本信息

字段protocol_version仅对HTTP上下文有效(HTTP 1.0与1.1),但不会影响SSL上下文。

以下手册页列出了PHP的所有流上下文选项: Context options and parameters

对于所有基于SSL的流包装器,只有以下选项可用: SSL context options

可能的解决方案/解决方法

第一个建议:让服务器管理员修复他的服务器而不是在你的客户端解决这个问题; - )

也许你可以使用ciphers option来处理SSL流,只能在目标服务器支持的列表中传递一个精确的TLSv1.0 cipher suite(TLSv1.0中唯一的)。

将实现切换为使用cURL最有可能也没有帮助,因为根据an entry in their mailing list,没有强制某个TLS版本的选项 - 客户端会在需要时自动降级。

<强> TL;博士

我目前知道无法明确强制TLSv1.0进行PHP的SSL连接。

答案 3 :(得分:0)

我可以确认上面接受的答案对Ubuntu 12.04和PHP 5.4.33组合不起作用。还发现在尝试openssl和curl访问https端点时我必须手动指定证书。当我开发企业应用程序的集成时,我最终使用RHEL 7和PHP 5.5来实现可靠的解决方案。对Ubuntu没有任何反对意见,但在我的具体情况下它并没有起作用。