Search code examples
phpsslcurlpaypalpaypal-ipn

PayPal's recent TLS 1.2 / HTTP 1.1 updates and when to use it


With regards to Paypal's recent security update I have started adding two additional options to my cURL code, those being:

curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_SSLVERSION, 6);

I set CURLOPT_HTTP_VERSION since not setting it seems to default to "lets CURL decide which version to use" - whilst I don't want or like to hardcode the setting for future compatibility reasons, can cURL be trusted to always set HTTP 1.1 if support is available?

Secondly, I set CURLOPT_SSLVERSION to 6, which is CURL_SSLVERSION_TLSv1_2 because I have read that..

Some environments may be capable of TLS 1.2 but it is not in their list of defaults, so need the SSL version option to be set.

Now, an additional query is I notice at that PayPal link it only makes mention of endpoints, but how about when you're making cURL requests to their other URL's like the common: https://www.paypal.com/cgi-bin/webscr used for things such as IPN listeners? Does that still require TLS 1.2 and HTTP 1.1?


Solution

  • www.paypal.com is using HTTP/2 as seen in

    curl --silent --head https://www.paypal.com | head -n 1
    HTTP/2 302
    

    According to official docs, your best option is

    CURL_HTTP_VERSION_2_0

    Attempt HTTP 2 requests. libcurl will fall back to HTTP 1.1 if HTTP 2 can't be negotiated with the server.

    cURL will fallback to the required HTTP/1.1 if HTTP/2 can not be used.

    curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
    

    This option could be even better

    CURL_HTTP_VERSION_2TLS

    Attempt HTTP 2 over TLS (HTTPS) only. libcurl will fall back to HTTP 1.1 if HTTP 2 can't be negotiated with the HTTPS server. For clear text HTTP servers, libcurl will use 1.1. (Added in 7.47.0)

    For php cURL extension docs

    CURL_HTTP_VERSION_2 (integer) Available since PHP 7.0.7 and cURL 7.43.0 CURL_HTTP_VERSION_2TLS (integer) Available since PHP 7.0.7 and cURL 7.47.0

    If your PHP version does not define those constants you can try something like

    defined('CURL_HTTP_VERSION_2_0') || define('CURL_HTTP_VERSION_2_0', 65536);
    

    For CURL_HTTP_VERSION_2TLS the value seems to be.

    CURL_HTTP_VERSION_2TLS = 4
    

    Using the integer value instead of the PHP constant could work as long as the libcurl backing package version supports it.

    On rpm based Linux you can check with

    rpm -q libcurl4
    libcurl4-7.60.0-lp150.2.6.1.x86_64
    

    Comparing with PHP (command line)

    php -r 'phpinfo();' | grep -i 'curl info'
    cURL Information => 7.60.0
    

    also with

    php -r 'print_r(curl_version());' | grep 'version'
    [version_number] => 474112
    [ssl_version_number] => 0
    [version] => 7.60.0
    [ssl_version] => OpenSSL/1.1.0h
    [libz_version] => 1.2.11