How do we specify TLS/SSL options in Guzzle?
Asked Answered
C

3

19

We are starting to use Guzzle in PHP with code which calls a variety of different APIs, a few of which don't support TLSv1.2 and some of which require TLSv1.2.

What's the best way to force Guzzle to use the most recent protocol available, except in cases where we know it won't be recognized?

Churchyard answered 14/10, 2015 at 19:46 Comment(0)
A
22

It is simple and easy.

$client = new Client();
$guzzle = new GuzzleClient('https://www.yourweb.com', array(
    'curl.options' => array(
        CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2
    )
));
$client->setClient($guzzle);
...

In Guzzle 3.0+ (update as per @limos' comment):

'curl' => array(
    CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2
)

The possible CURLOPT_SSLVERSION options can be found at the official cURL page: http://curl.haxx.se/libcurl/c/CURLOPT_SSLVERSION.html

--- UPDATE (based on the comments) ---

Choosing proper SSL protocol version involves not just the CURLOPT_SSLVERSION setting, but a lot more cURL settings. The desired and important result is called "Maximum forward secrecy". This is valid not just for cURL!

You can't use multiple CURLOPT_SSLVERSION parameters (at least, I didn't find such option in the Guzzle documentation). When you define CURLOPT_SSLVERSION, cURL will make an attempt to use that SSL version - from the cURL documentation (the link provided above about the CURLOPT_SSLVERSION) - "Pass a long as parameter to control which version of SSL/TLS to attempt to use."

You can define multiple secure ciphers, but only one SSL version parameter. I wouldn't use anything earlier than TLS 1.1. Any earlier SSL version is vulnerable to attack. Version TLS 1.1 is also vulnerable, but then you might run into client compatibility issues at 1.2, if you go that route. The only secure (for now, until they discover some vulnerability) is TLS 1.2.

If security is top priority, go with the highest available TLS version (TLS1.2). Client compatibility is not your problem when there is service provider security liability.

If security is important, here are other cURL options to look at:

Setting proper CURLOPT_SSL_VERIFYHOST and CURLOPT_SSL_VERIFYPEER will prevent MITM attacks.

CURLOPT_CAINFO - Fix Error: 35 - Unknown SSL protocol error in connections. Improve maximum forward secrecy.

Here's a list with cURL ciphers (CURLOPT_SSL_CIPHER_LIST) to look into, which will improve maximum forward secrecy:

'DHE-RSA-AES256-SHA',
'DHE-DSS-AES256-SHA',
'AES256-SHA',
'ADH-AES256-SHA',
'KRB5-DES-CBC3-SHA',
'EDH-RSA-DES-CBC3-SHA',
'EDH-DSS-DES-CBC3-SHA',
'DHE-RSA-AES128-SHA',
'DHE-DSS-AES128-SHA',
'ADH-AES128-SHA',
'AES128-SHA',
'KRB5-DES-CBC-SHA',
'EDH-RSA-DES-CBC-SHA',
'EDH-DSS-DES-CBC-SHA:DES-CBC-SHA',
'EXP-KRB5-DES-CBC-SHA',
'EXP-EDH-RSA-DES-CBC-SHA',
'EXP-EDH-DSS-DES-CBC-SHA',
'EXP-DES-CBC-SHA'

These ciphers were checked against the strong Qualys SSL Labs list (2014) and weak ciphers were removed. Feel free to add/remove any ciphers.

If you still want to pursue multiple CURLOPT_SSLVERSION options, I would write a script to do so (which, I don't think it is a good practice or necessary). But still, if you decide to pursue that functionality for any reason, write some code which will attempt to use the strongest possible SSL encryption and then fallback to the next version, if it fails to connect.

  1. Before you make a decision take a look at the Qualys SSL Labs' projects about security.
  2. Take a look at this SSL Labs' article about perfect forward secrecy and best practices.
  3. Test your client (web browser) for any vulnerabilities with SSL Labs' web tool. This will give you an idea what to look at and what to improve and secure on your server and app.
  4. Test your website/web service with Qualys' SSL Labs SSL tool.

Vulnerabilities and attacks: Longjam, FREAK, POODLE, you name it! Who knows what other attacks or vulnerabilities are undiscovered? Yes! They all affect your choice of SSL/TLS connection.

You have no control over the client (unless you develop it), but you have control over the server and server-client negotiations.

No matter what app you build, you should look at best practices, depending on your needs and per case basis, you should decide on the following options:

  1. Security
  2. Compatibility
  3. Maintainability
  4. Complexity

If security is so important, go with TLS1.1 at minimum. Look at cipher lists also, I wouldn't overlook that part.

Here's also a nice OWASP guide for creating a secure layer around your app.

OWASP and Qualys SSL Labs are great resources to start with. I would even do some research on cURL and OpenSSL to get familiar with weaknesses, possible security options and best practices.

There are security points, which I am not mentioning and are missing, but we can't cover everything. This is just the tip of the iceberg. Anything not mentioned here is for you to research.

Good Luck!

I will be around to answer any questions, if I can.

Archaize answered 14/10, 2015 at 20:4 Comment(6)
OK, so we can either have it auto-negotiate (default) OR set only a single protocol version to accept? I was hoping there might be a way to give it a set of protocol versions and have it choose the most recent.Churchyard
Correct, you can't use multiple CURLOPT_SSLVERSION parameters (at least, I didn't find such option in the Guzzle documentation). When you define CURLOPT_SSLVERSION, cURL will make an attempt to use that SSL version. From the cURL documentation (the link provided) "Pass a long as parameter to control which version of SSL/TLS to attempt to use." You can define multiple secure ciphers, but only one ssl version parameter. I wouldn't use anything earlier than TLS 1.1. Any earlier SSL version is vulnerable to attack. v1.1 is also vulnerable, but then we'll run into client compatibility issues at 1.2Archaize
I decided to update my answer, because there's no simple answer to your question.Archaize
Just to add - in Guzzle 3.0 the key is 'curl' not 'curl.options'. Also, the constants should be without quotesCroon
@Croon Good catch. Thanks for pointing that out! I made the updates. :)Archaize
How works this on Guzzle >= 7.0.1?Raiment
T
12

In Guzzle 5.3, I had to use this syntax:

$guzzle = new \GuzzleHttp\Client([
    'defaults' => [
        'config' => [
            'curl' => [
                CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2
            ]
        ]
    ]
]);
Tetravalent answered 4/5, 2016 at 9:47 Comment(0)
A
4

In Guzzle 7, it can be set directly under curl as Request Options, which is not mentioned in the documentation:

$client = new \GuzzleHttp\Client();
$res = $client->request('GET', 'https://www.howsmyssl.com/a/check', [
    'curl' => [
        CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2
    ],
]);
$body = $res->getBody();
echo ($body ? json_decode($body, true)['tls_version'] : "Request failed");

In addition, if you would like to specify a minor TLS version, you can use the max options, e.g. CURL_SSLVERSION_MAX_TLSv1_1.

CURL option reference: CURLOPT_SSLVERSION explained

Reference: Guzzle soruce code

Antihero answered 24/8, 2022 at 8:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.