cURL中的TLS 1.2无法工作

28

我在使用curl时遇到了问题,无法对使用TLS1.2的HTTPS url进行操作。我的curl操作是将登录数据发布到网站上,并将其保存在cookiefile中。我收到的错误消息是:

 error:14077438:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert internal error
我尝试将 VERIFYPEERVERIFYHOST 设置为0,但似乎没有起作用,你有什么建议吗?
我使用的版本如下:
  • OpenSSL版本是0.9.8b
  • CURL版本是7.24.0
  • PHP版本是5.3
以下是代码:
$setuplogin = curl_init(); 
curl_setopt ($setuploginurl, CURLOPT_URL, $url); 
curl_setopt ($setuploginurl, CURLOPT_SSL_VERIFYPEER, 1); 
curl_setopt ($setuploginurl, CURLOPT_SSL_VERIFYHOST, 1);
curl_setopt ($setuploginurl, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt ($setuploginurl, CURLOPT_SSLVERSION, 'CURL_SSLVERSION_TLSv1_2');
curl_setopt ($setuploginurl, CURLOPT_POSTFIELDS, 'username=uname&password=pword&act=login&submit=Login');
curl_setopt ($setuploginurl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36"); 
curl_setopt (setuploginurl, CURLOPT_TIMEOUT, 60); 
curl_setopt ($setuploginurl, CURLOPT_COOKIESESSION, TRUE); 
curl_setopt ($setuploginurl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($setuploginurl,  CURLOPT_HEADER, 1);
curl_setopt ($setuploginurl,CURLOPT_ENCODING,"gzip");
curl_setopt ($setuploginurl, CURLOPT_POST, true);
curl_setopt ($setuploginurl, CURLOPT_COOKIEJAR, 'cookies.txt'); 
curl_setopt ($setuploginurl, CURLOPT_FRESH_CONNECT , 1);

$loginp= curl_exec($setuploginurl); 
if ($loginp === FALSE) {
    die(curl_error($setuploginurl));
}

curl_close ($setuploginurl); 
var_dump ($loginp);

2
你应该使用数字2来代替数字1,作为CURLOPT_SSL_VERIFYHOST的参数。 - Bruno
我不知道这是否是自动的,但切换到 PHP v 5.6.33 解决了我的问题。 - HasanG
6个回答

56

您必须使用整数值作为CURLOPT_SSLVERSION值,而不是如上所列的字符串。

请尝试这样做:

curl_setopt ($setuploginurl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); // constant NOT string value

http://php.net/manual/zh/function.curl-setopt.php

以下选项参数的值应该是整数:CURLOPT_SSLVERSION

其中之一:

CURL_SSLVERSION_DEFAULT (0)
CURL_SSLVERSION_TLSv1 (1)
CURL_SSLVERSION_SSLv2 (2)
CURL_SSLVERSION_SSLv3 (3)
CURL_SSLVERSION_TLSv1_0 (4)
CURL_SSLVERSION_TLSv1_1 (5)
CURL_SSLVERSION_TLSv1_2 (6)

8
您仍然可以使用CURL_SSLVERSION_TLSv1_2 - 只需要将其作为常量,即不需要加引号。对于我而言,curl_setopt ($setuploginurl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);可以正常工作。 - But those new buttons though..
3
CURL_SSLVERSION_TLSv1_2 可从 PHP 5.5.19 使用,在 PHP 5.3 中无效。 - Kavin D
非常感谢您发布这个...帮了我大忙! - born2net
@KavinD 这个常量最初是在 PHP 5.5.19 和 5.6.3 版本中添加的。 - Darren Felton

29

TLS 1.1 和 TLS 1.2 自 OpenSSL 1.0.1 起得到支持。

强制使用 TLS 1.1 和 1.2 自 curl 7.34.0 起得到支持。

建议您进行升级。


3
Curl在版本7.34.0中才开始支持TLS 1.2。 - Hannele
1
升级到OpenSSL 1.0.1解决了我类似的问题。 - OfficeAddinDev
2
为了在Centos 6.4上使其正常工作,必须执行yum update nss openssl curl。 - LP Papillon
1
@LPPapillon 非常感谢! :) 这也为我解决了错误 :) - Jovan Perovic
2
@hannele,您指定的文档是用于强制TLS 1.2的。Libcurl在早期版本中支持此协议。 - asafd
显示剩余2条评论

15

我在Stripe的情境下遇到了类似的问题:

错误:Stripe不再支持使用TLS 1.0进行的API请求。请使用TLS 1.2或更高版本发起HTTPS连接。您可以在https://stripe.com/blog/upgrading-tls了解更多信息。

使用CURL参数强制使用TLS 1.2是临时解决方案,甚至可能由于没有更新空间而无法应用。默认情况下,TLS测试函数https://gist.github.com/olivierbellone/9f93efe9bd68de33e9b3a3afbd3835cf显示以下配置:

SSL version: NSS/3.21 Basic ECC
SSL version number: 0
OPENSSL_VERSION_NUMBER: 1000105f
TLS test (default): TLS 1.0
TLS test (TLS_v1): TLS 1.2
TLS test (TLS_v1_2): TLS 1.2

我使用以下命令更新了库:

yum update nss curl openssl

然后看到了这个:

SSL version: NSS/3.21 Basic ECC
SSL version number: 0
OPENSSL_VERSION_NUMBER: 1000105f
TLS test (default): TLS 1.2
TLS test (TLS_v1): TLS 1.2
TLS test (TLS_v1_2): TLS 1.2

请注意,默认的TLS版本已更改为1.2!这在全球范围内解决了问题。这也将有助于PayPal用户:https://www.paypal.com/au/webapps/mpp/tls-http-upgrade(在2017年6月底之前更新)


只是想补充一下,你需要在此之后重启 Apache。谢谢。 - Jaspal Singh

2

TLS 1.2 只在 OpenSSL 1.0.1 或者更新版本中受支持(请查看主要版本发布章节),所以您需要更新您的OpenSSL

不需要设置 CURLOPT_SSLVERSION 选项。请求会进行握手协议,并使用服务器和客户端都支持的最新的 TLS 版本。如果您的OpenSSL版本为 1.0.1 或更高,则您的php_curl将默认使用 TLS 1.2,因为您所请求的服务器正在使用TLS 1.2


1
为了强制使用特定的TLS版本,我们需要使用CURL_SSLVERSION_MAX_TLSv...而不是CURL_SSLVERSION_TLSv...
curl_setopt ($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_MAX_TLSv1_2);

这是一个修改自@Tomasz Dobrzyński的脚本。

<?php

function get_tls_version($tlsVersion)
{
    $c = curl_init();
    curl_setopt($c, CURLOPT_URL, "https://www.howsmyssl.com/a/check");
    curl_setopt($c, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($c, CURLOPT_SSLVERSION, $tlsVersion);
 
    $rbody = curl_exec($c);
    if ($rbody === false) {
        $errno = curl_errno($c);
        $msg = curl_error($c);
        curl_close($c);
        return "Error! errno = " . $errno . ", msg = " . $msg;
    } else {
        $r = json_decode($rbody);
        curl_close($c);
        return $r->tls_version;
    }
}

echo "OS: " . PHP_OS . "\n";
echo "uname: " . php_uname() . "\n";
echo "PHP version: " . phpversion() . "\n";

$curl_version = curl_version();
echo "curl version: " . $curl_version["version"] . "\n";
echo "SSL version: " . $curl_version["ssl_version"] . "\n";
echo "SSL version number: " . $curl_version["ssl_version_number"] . "\n";
echo "OPENSSL_VERSION_NUMBER: " . dechex(OPENSSL_VERSION_NUMBER) . "\n";

echo "\nTesting CURL_SSLVERSION_TLSv... (not forced)\n";
echo "Result TLS_Default: " . get_tls_version(CURL_SSLVERSION_DEFAULT) . "\n";
echo "Result TLS_v1_1: " . get_tls_version(CURL_SSLVERSION_TLSv1_1) . "\n";
echo "Result TLS_v1_2: " . get_tls_version(CURL_SSLVERSION_TLSv1_2) . "\n";
echo "Result TLS_v1_3: " . get_tls_version(CURL_SSLVERSION_TLSv1_3) . "\n";

echo "\nTesting CURL_SSLVERSION_MAX_TLSv...\n";
echo "Result MAX_Default: " . get_tls_version(CURL_SSLVERSION_MAX_DEFAULT) . "\n";
echo "Result MAX_TLS_v1_1: " . get_tls_version(CURL_SSLVERSION_MAX_TLSv1_1) . "\n";
echo "Result MAX_TLS_v1_2: " . get_tls_version(CURL_SSLVERSION_MAX_TLSv1_2) . "\n";
echo "Result MAX_TLS_v1_3: " . get_tls_version(CURL_SSLVERSION_MAX_TLSv1_3) . "\n";

结果

OS: WINNT
uname: Windows NT 10.0 build 19043 (Windows 10) AMD64
PHP version: 7.4.29
curl version: 7.70.0
SSL version: OpenSSL/1.1.1l
SSL version number: 0
OPENSSL_VERSION_NUMBER: 101010cf

Testing CURL_SSLVERSION_TLSv... (not forced)
Result TLS_Default: TLS 1.3
Result TLS_v1_1: TLS 1.3
Result TLS_v1_2: TLS 1.3
Result TLS_v1_3: Error! errno = 35

Testing CURL_SSLVERSION_MAX_TLSv...
Result MAX_Default: TLS 1.3
Result MAX_TLS_v1_1: TLS 1.1
Result MAX_TLS_v1_2: TLS 1.2
Result MAX_TLS_v1_3: TLS 1.3

0

替换以下内容

curl_setopt ($setuploginurl, CURLOPT_SSLVERSION, 'CURL_SSLVERSION_TLSv1_2');

使用

curl_setopt ($ch, CURLOPT_SSLVERSION, 6);

应该无缝运行。


10
不要这样做。你正在将一个对于阅读代码的人来说毫无意义的整数硬编码进去。相反...只需删除单引号并使用常量即可。 - HTMLGuy

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