Some time ago I wrote all about the main risks in using SSL/TLS in PHP and here’s one of the more relevant quotes:
As much as I love PHP as a programming language, the briefest survey of popular open source libraries makes it very clear that Transport Layer Security related vulnerabilities are extremely common and, by extension, are tolerated by the PHP community for absolutely no good reason other than it’s easier to subject users to privacy-invading security violations than fix the underlying problem. This is backed up by PHP itself suffering from a very poor implementation of SSL/TLS in PHP Streams which are used by everything from socket based HTTP clients to file_get_contents() and other filesystem functions. This shortcoming is then exacerbated by the fact that the PHP [manual] makes no effort to discuss the security implications of SSL/TLS failures.
If you take nothing else from this section, my advice is to make sure that all HTTPS requests are performed using the CURL extension for PHP. This extension is configured to be secure by default and is backed up, in terms of expert peer review, by its large user base outside of PHP. Take this one simple step towards greater security and you will not regret it. A more ideal solution would be for PHP’s internal developers to wake up and apply the Secure By Default principle to its built-in SSL/TLS support.
Yes. My honest recommendation is that if you intend using a secure connection, for example a request over HTTPS, just don’t use PHP sockets or streams. The problems with PHP’s implementation are widely known but it’s perhaps captured best by the then inability of PHP’s SSL layer to verify a perfectly valid certificate using Subject Alternative Names as used for Packagist.org. Simply put, if nobody noticed that glaring flaw outside of one high profile case then they were never going to notice its less obvious shortcomings.
So, I was very excited to see the following commit on Github to PHP’s source code yesterday evening: https://github.com/php/php-src/commit/6edc84fcdfc8e76507bc73122310fff4b6170b88
This commit implements the TLS Peer Verification RFC for PHP 5.6 that was voted through (25-0) as 2013 drew to a close. The RFC reverses PHP’s course and provides PHP streams with defaults that enable both peer verification and host verification. The patch implements the RFC and it lets PHP leverage the local system’s own certificate stash (e.g. Debian’s ca-certificates) where possible to avoid PHP having to distribute a bundle of its own and while also assisting in backwards compatibility.
Once we have a PHP streams/sockets system with a passable level of default security, the rest will be left to programmers on the ground to change their practices. For example, back in March 2013, PHP 5.4.13 introduced a new SSL Context option “disable_compression” so that programmers could defend their applications against CRIME attacks which includes the more recent BREACH attack.
I hopped on Github this morning out of interest and ran a search for this context option. Bearing in mind that Github may be malfunctioning and that all viewers of these results may be hallucinating as a group, I was a bit alarmed at seeing one result. Just one. Out of all the PHP code publicly hosted on Github. One. If this search is in anyway accurate, it means that there is a vast body of PHP code (as in all of it using SSL/TLS over PHP streams/sockets except ONE) which is vulnerable to CRIME/BEAST attacks irrespective of the PHP version it runs on.
That’s not just sad, it’s just…just… Damn it! Let me try that search again. DAMN IT!
Seriously, dear readers, all the improvements to PHP’s SSL/TLS security dropping for PHP 5.6 mean absolutely NOTHING if programmers will not actually use them. So please, start your editors.
- Yahoo encryption mocked by many (news.techeye.net)
- Mass surveillance prompts IETF work on SSL deployment guidelines (computerworld.co.nz)
Scanning the blogs today, I noticed an article discussing a method of implementing Stateless CSRF protection. Stateless CSRF defences are required in applications where the user has no session. That might sound a bit weird, but not all applications require sessions and their architecture may be such that they do not synchronise session data across servers.
The difference between Stateful and Stateless CSRF defences is that the former requires storing the CSRF token on the server (i.e. session data) while the latter does not, i.e. the server has zero record of any CSRF tokens. As far as the server is concerned, the number of parties with persistent knowledge of a valid token is reduced to just one – the client.
Let’s compare both types of CSRF protections.
Stateful CSRF Defence: Synchronizer Token Pattern
On all POST requests, the user will submit a valid CSRF token as part of the POST data. The server completes the CSRF defence by ensuring that the submitted token is identical to the stored copy. Unless the attacker can successfully guess the token, their CSRF attacks are rendered useless.
Stateless CSRF Defence: Double Submit Pattern
In a stateless CSRF defence, what’s really important is that requests are verified as being initiated by the client. We accomplish this by using the Double Submit method of preventing CSRF.
In a Double Submit, the client submits two tokens back to the server. The first is submitted in the POST data, the second is sent as cookie data. Since the attacker has no idea what cookie data your browser has and can’t fake cookie values in a CSRF attack, the attacker only has the ability to guess what token to inject into POST data being submitted during a CSRF attack – which won’t agree with the cookie token. The server will compare the token contained in the POST data with the token from the cookie data and check that they are identical.
Simply put, we’ve switched the token storage location. Stateful CSRF defences involve storing it in session data on the server while Stateless defences need the client to store it in a cookie (with the HttpOnly flag enabled and the cookie suitably limited by subdomain or domain). Either way, we end up with the same results – two tokens for comparison, of which one always remains unknown to the attacker.
Stateful Stateless CSRF Tokens
In the blog post I read this morning, there are two fundamental problems in the proposed stateless defence. The first was assuming that WordPress’ nonce feature made a good anti-CSRF defence model (the function doesn’t actually generate good tokens let alone real nonces). The second was not recognising its departure from the Double Submit approach.
The method suggested in the blog post generates a CSRF token by hashing together inputs which include server time in seconds, a user ID, a validity period in seconds, and a textual element like an action description. These elements are all determined by the server and they share something in common – they represent server knowledge or state. This is NOT stateless. You are still directly reliant on the server storing inputs to the token generation routine which may well be identical per user or determined by publicly accessible user information (e.g. IP address).
If you assess each input to the token individually… Time is predictable and linear. User IDs may have limited range, have been previously enumerated using a timing attack against your login logic, or be non-existent in a truly stateless application. Text descriptions are probably fixed and may be either known in advance or be subject to brute forcing or harvesting. This tells the tale of an extremely bad and dangerous generating mechanism vulnerable to brute forcing due to the lack of sufficient entropy. CSRF tokens MUST be random. If they are not randomly generated, then you are doing something wrong. In this case, the need for the convenience of a reconstructable token overrode the need for securing tokens against brute forcing.
The token is submitted with POST request data (single submit – not a double submit) and the server must then reconstruct the token in order to perform a comparison. The reconstruction requires that the server have some shared state or data harvesting which acts like a seed. Crack the seed and the defences for all users will be utterly devastated.
Double Submit and Random Tokens Are Inseparable Partners
Like most attacks, CSRF does not exist in isolation so developing a good defence requires mitigating other attacks. CSRF tokens needs to resist brute forcing by using sufficient entropy to be decently random, they must be stored securely, and you must never share tokens between HTTP and HTTPS sessions. Any good CSRF token implementation, whether stateful or stateless, should reflect those requirements with features for limiting tokens by scope and time.