Programmable Infrastructure Vs Infrastructure As Code

Programmable Infrastructure Vs Infrastructure As Code

Programmable Infrastructure, Infrastructure as Code? If you’ve never heard of these terms, you’re probably wondering what the hell they are. There is no competition between the 2 phrases as they both refer to the same concept dependent on which side of the buzz word fence you want to sit on. For the remainder of this article, I choose to use the phrase Infrastructure As Code as it’s easier on the tongue. 🙂

With the advent of cloud services such as Amazon EC2 and Google Cloud Platform with simple exposed APIs and SDKs (if available) and infrastructure management tools such as Puppet, Chef, Docker containers etc.., gone are the days when a tech company needed to hire dedicated system administrators to manage the infrastructure layer of their software platform (Financial controllers love to hear this kind of stuff). Now, all a tech company needs is a developer with an understanding of APIs and SDKS to write code to provision, deploy and manage infrastructure services. This is what Infrastructure as Code boils down to.

Of course you could argue that the developer nirvana described above is nothing short of configuration management, but 2 main differences with Infrastructure as Code are:

  • It is fully automated
  • A developer can build the infrastructure blueprint directly into the core of an application or into the build / deploy component of an application simply by writing code that describes the infrastructure. (Now isn’t that awesome!)

A typical highly simplified application workflow that takes advantage of Infrastructure as Code could be along the lines of this:

Infrastructure As Code offers a number of advantages to a development team looking to take their ninja DevOp skills to the next level, a few of which are:

  • You end up with documentation that describes your infrastructure from which you can generate other representations of your infrastructure such as pretty diagrams. (Don’t we all love pretty diagrams!)
  • You only need to look in one consistent place to make changes to your infrastructure which makes maintenance a breeze
  • You can chop and change your infrastructure at the speed at which it takes your developers to write code against an alternative API whether internal or external

You might ask if Infrastructure As Code is a concept worth adopting in your tech company or in your DevOps team, but it surely does offer a level of flexibility and raw infrastructure management power that you’ll find hard to ignore. If you haven’t already, join the bandwagon.

Kamba Abudu
26 Jun 2016

SSL and PHP Streams – You Are Doing It Wrong

SSL and PHP Streams – You Are Doing It Wrong

The upcoming PHP 5.6 release brings with it a number of improvements to encrypted PHP streams, both internally and externally. In these articles I will try to cover the most important changes, and how they affect your code.

This article will focus on how to get the best security level in code that needs to be run on PHP versions below 5.6, and highlighting some of the gaps in the currently available functionality. Version 5.4.13 is the earliest version that supports all the options described below – and if you are running something earlier than this, then you really should consider upgrading to at least the latest version of the 5.4 series¹.

Client Communication

PHP provides some very simple APIs to use encrypted connections for client communication. It lets you make an encrypted HTTP request to retrieve some data with just one line of code:

<?php

$data = file_get_contents(‘https://example.com/file.ext’);

Great! We just retrieved some data from a remote server in completely secure manner, right? Wrong.

Problem 1: Peer verification

One of the most important parts of using encrypted connections is verifying that the remote peer you are communicating with is really who they say they are, and who you are expecting them to be. Without this crucial step, man-in-the-middle (MITM) attacks are trivial, and even though the data arrives on your machine encrypted it could have been stolen or altered by a 3rd party along the way.

If you’ve ever tried to use the cURL extension to retrieve an HTTPS resource, chances are you’ve seen this message:

SSL certificate problem, verify that the CA cert is OK. Details: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

That’s because cURL attempts to verify and validate the certificate presented by the server and fails to do so, usually because it cannot be traced back to a trusted root certificate authority (CA). Often this is because the root certificate authority list is not installed or not correctly configured. A little research will then lead you to configure the `curl.cainfo` setting with a valid CA file, and your code will now work as expected.

But what about streams? If you make the same request using streams it works without complaining, so that’s clearly a better option – except it isn’t, because before PHP 5.6, PHP streams do not attempt to verify the peer certificate by default! This doesn’t mean the streams are fundamentally insecure, it just means you need to use stream context options to make them secure.

Let’s update our code to verify the peer certificate against a list of trusted root certificate authorities:

<?php

$contextOptions = [
‘ssl’ => [
‘verify_peer’ => true,
‘cafile’ => ‘/path/to/cafile.pem’,
‘CN_match’ => ‘example.com’,
]
];
$context = stream_context_create($contextOptions);

$data = file_get_contents(‘https://example.com/file.ext’, false, $context);

This allows us to verify the server’s certificate against a trusted CA chain. Setting `verify_peer` to `true` instructs PHP to perform the verification process, and the `cafile` option supplies the trusted CA data to verify against. This can also be specified using the `capath` option, which allows you to store the trusted certificates in separate files in the specified directory. More details of how this needs to be formatted are available at openssl.org.

We must also specify the expected peer name on the presented certificate with the `CN_match` option, it will not be inferred from the URL and if it is not specified, the name on the certificate will not be validated. It must match the Common Name field of the certificate, the Subject Alternative Names field will not be considered – this is a pretty major limitation on the modern internet.

There is currently no mechanism for verifying a certificate fingerprint.

Download your free e-book
Problem 2: Cipher lists

There are many different ways to encrypt data – many different algorithms with many different sub-variants. PHP simply lets OpenSSL deal with this problem, by specifying `DEFAULT` as the list of acceptable algorithms (cipher list). Unfortunately, this list allows almost anything, including a number of very weak ciphers that can be easily broken by a determined attacker, allowing them to steal data.

The `ciphers` context option allows us to specify a list of acceptable ciphers to use with the connection – if one of these cannot be negotiated by both server and client, the connection will fail before any potentially sensitive data is transmitted. Let’s update our code so specify that only `HIGH` encryption cipher suites may be used ²:

<?php

$contextOptions = [
‘ssl’ => [
‘verify_peer’ => true,
‘cafile’ => ‘/path/to/cafile.pem’,
‘CN_match’ => ‘example.com’,
‘ciphers’ => ‘HIGH’,
],
];
$context = stream_context_create($contextOptions);

$data = file_get_contents(‘https://example.com/file.ext’, false, $context);

An explanation of the format and available options for the cipher list is available at openssl.org. Mozilla’s recommended cipher list for servers is published here.

Problem 3: Protocol support

PHP streams support SSL versions 2 and 3, and TLS version 1.0 3. Moreover, it’s not possible to directly specify which protocol will be used with an `https://` or `ftps://` connection. SSLv2 is very broken, and SSLv3 is also less than desirable. On the modern internet, there are very few servers that do not support at least TLS version 1.0.

While it’s not currently possible to directly specify which protocol to use, it is possible to forbid them using the cipher list, so lets update our code to require TLS:

<?php

$contextOptions = [
‘ssl’ => [
‘verify_peer’ => true,
‘cafile’ => ‘/path/to/cafile.pem’,
‘CN_match’ => ‘example.com’,
‘ciphers’ => ‘HIGH:!SSLv2:!SSLv3’,
],
];
$context = stream_context_create($contextOptions);

$data = file_get_contents(‘https://example.com/file.ext’, false, $context);

When creating raw socket streams it is possible to directly specify the protocol to use, using either the approiate URI scheme (`sslv2://`, `sslv3://` or `tls://`) when creating the socket, or by using the appropriate constant when enabling encryption on an existing TCP socket via `stream_socket_enable_crypto()`.

Even so, our code does not support the more modern TLS version 1.1 and 1.2 protocols, which contain a number of security improvements over TLS version 1.0. Luckily, in practice, these security improvements are largely theoretical – the known attacks against TLSv1.0 can and do work, but they are currently impractical to execute in real life applications without a level of system compromise that would render the attack pointless – the attacker can already steal your data much more easily by this point.

Problem 4: TLS compression attack vulnerability

The CRIME attack vector against TLS can be easily mitigated by disabling protocol-level compression. Unfortunately, in PHP it’s enabled by default ³. Luckily, since PHP 5.4.13, it can be easily disabled using a simple boolean context option `disable_compression`. Let’s update our code to use it:

<?php

$contextOptions = [
‘ssl’ => [
‘verify_peer’ => true,
‘cafile’ => ‘/path/to/cafile.pem’,
‘CN_match’ => ‘example.com’,
‘ciphers’ => ‘HIGH:!SSLv2:!SSLv3’,
‘disable_compression’ => true,
],
];
$context = stream_context_create($contextOptions);

$data = file_get_contents(‘https://example.com/file.ext’, false, $context);

Server Communication

Using PHP for managing server streams is less common, but it is possible and has been for a long time. Problems 2, 3 and 4 described above also apply to server streams (problem 1 doesn’t come into play unless you require a client certificate) but there are other issues with server streams that are currently not resolvable in PHP.

Problem 5: Cipher order

Some attack vectors are only possible if certain ciphers are used. Currently PHP instructs OpenSSL to use the cipher priorities specified by the client, potentially leaving the server open to attack.

Download your free e-book
Problem 6: TLS renegotiation attacks

As problems go, this is a big one. SSL version 3 and all versions of TLS allow renegotiation of the connection settings after it has been created – changing protocol and cipher lists. This process is vulnerable to a limited MitM attack (an attacker can inject data but cannot see the response) and it also opens a denial-of-service (DoS) flaw on the server.

Negotiating a secure connection considerably more expensive for the server than it is for the client in terms of CPU cycles, meaning that anyone with a laptop can bring your super-powerful server down by simply repeatedly renegotiating the connection. Moreover, this potential DoS attack is very difficult to detect on the edge firewall or the server firewall, because it only requires a single TCP connection, and does not create excessive traffic on that link.

At present, PHP provides no way to disable renegotiation, or limit the rate at which renegotiation requests will be honoured.

Summing Up 

Using secure connections in PHP streams is not as simple as it appears on the surface. Our original “one line” of code is now a complex set of options. It’s harder to read, and it’s impossible to write it correctly without understanding precisely what the various options do.

In order to obtain an acceptable level of security, the user is required to understand some of the technical elements of the cryptography they are attempting to use. This can be a daunting, and as result many applications are deployed using insecure settings – some of them so bad as to almost completely negate the expense of use encryption in the first place.

In the next article, we’ll look at how some of the changes in PHP 5.6 will make life a lot simpler for the average PHP developer to create truly secure communication routines.

It is important to note that the code samples from the article do not represent the one true “correct” way to make your arbitrary HTTPS request. You *must* understand the implications of these options before you use them.

¹ At the time or writing, the current release in the 5.4 branch is 5.4.29. This release, along with the 5.5.13 sister release, contain a behavioural regression with unserialising strings which breaks (amongst other things) elements of PHPUnit and Doctrine. It’s probably best to avoid these specific releases, 5.4.30 and 5.5.14 should “fix the fix”.

² This is not a recommendation, merely an example, although it’s not a bad jumping-off point.

³ This does not necessarily mean that a given connection will be compressed, as the server can also refuse to honour the client’s request to compress the data.

Download our free e-book
Download our free e-book

Chris Wright
26 June 2015