Zend Framework

Storing Session Data In Cookies: Problems And Security Concerns To Be Aware Of

English: Peanut butter cookie with a chocolate...

Image via Wikipedia

Back from my extended leave of absence, I’ll re-open the dusty cobwebbed depths of this blog to echo the sentiments of Paul Reinheimer in his recent article “Cookies don’t replace Sessions“. The topic is actually an old one since Ruby On Rails has adopted the strategy of storing application session data in cookies by default (take note, performance hounds). The purposes of storing sessions in userland cookies rather than the conventional “stick-it-on-the-filesystem/database” used by many apps is one of performance and a little obscuration. Cookie data can be accessed faster than hitting the filesystem/database plus it has the dubious ability to disguise the session-targeted programming language. Really though, PHP is assumed to be on all web servers so hiding its existence is a bit like trying to hide an elephant in a zoo. Hide it all you want – we still know there has to be one in there!

In exchange for speeding up session reading, storing session data in cookies has some fairly uncomfortable costs.

Now, developers are not unaware of the problems of storing potentially sensitive application data in plain text files on the user’s PC which users can manipulate, copy, and mangle to their (or the hacker’s currently fiddling with the user’s PC) heart’s content. It’s dangerous depending on just how much you rely on session data to drive other security rules or restrictions on business logic within the application. Technically, the reliance placed on sessions should be close to nothing – session data should drive the application towards other storage solutions for the really essential stuff and just stay around as a minimal identifier/stash of basic ID info. Such minimal information can be dumped, corrupted, or overwritten with the only cost being to perhaps require a user to login again when that happens. Stuffing a bank balance into a session, on the other hand, is one (very exaggerated!) example of the kind of data you should be shot for relying on a session for.

Programmers being programmers, it’s not rare to see sessions become a more intrinsically important storage location than it should be. In those cases, being able to manipulate the session data can become a problem and may give rise to exploitation scenarios where tampering with the stored data leads to some benefit for the manipulator. Obviously we want to make sure that that can’t happen even in scenarios where programmers may be a bit loose with where they store data. We don’t build frameworks and libraries for Gurus, we build them for all programmers – even the sometimes ignorant and under trained ones. This cookie stored session data is often coupled with the ability to encrypt that data. However…

As Paul Rainheimer remarks in his article, “Encryption is often viewed as a panacea for security problems, you sprinkle a little encryption dust around, and your problems dissolve”. This is an absolute truth in programming – programmers often view encryption as a solution without regard for one teeny tiny problem. If you encrypt a set of data for any purpose, even though it’s encrypted, the user (or the hacker hacking the user’s account) still has the data in some usable form!

With perfectly intact data, and even through it’s hidden by encryption, that data can be recycled simply by copying it to another machine. Depending on the data that is stored (which admittedly may require the hacker/user to figure out by doing actual work like finding your open source app on Github or breaking a developer’s fingers until they spill the beans), you can restore past data just by copying over a backup of a prior cookie or repeat a past transaction by continually reusing the original cookie it required. Paul offers a few trivial examples in his article.

Such reuse of data is known as a replay attack. A scenario where even encrypted data can be constantly reused to give rise to a positive result – all without any need whatsoever to break the encryption. The antidote to this vulnerability is to ensure that all data sets are unique and can be used only once, i.e. you include a single-use nonce (some generated set of characters or bits) in the data which is updated whenever that data is used. This continually forces the update of the relevant digital HMAC signature and/or encryption result (even for the exact same data otherwise) in order to prevent any reuse of old data in a replay attack. Once a nonce is used, it’s discarded, and the old data can no longer be accepted by your application. Of course, the downside is that since the nonce must be single-use, you need to keep track of all nonces to ensure they are not accidentally used again. You will need a database, possibly using a nonce-included timestamp as a time limit so your storage requirements aren’t completed insane, which obviously means that just using the traditional database storage for sessions in the first place would have been a much better and simpler choice.

So, in summary, encryption prevents the reading of data but it does not prevent the reuse of existing data. For that to be prevented you need a nonce implementation. And, due to the complexity of using and tracking nonces, practically no cookie stored session solutions will actually offer nonce support because it would eliminate their speed advantage. Which means they are susceptible to replay attacks, which means they are dangerous tools to be swinging around blindly, which means that the old local session storage strategies are still far superior from a security perspective, which all means that you should avoid cookie stores like the damned plague and stick to the old, traditional but secure session storage strategies we already have unless you a) are crazy or b) trust your colleagues (and yourself) not to screw it up.

Even without the security concerns, there is also another less critical downside to storing sessions in cookies which is that cookies have a storage limit of around 4KB. No other storage solution for session data should have that problem but you need to be aware of it anyway as using encryption may push you there sooner than the base data size might suggest (encrypted data size is usually larger than the original data). While noting this, you should never really hit that limit unless you are storing data there that you likely shouldn’t be anyway!

So, cookie based session storage: It’s very fast but lethally insecure if you store the wrong type of data. If you’re going to use it, make sure you keep a tight rein on what data is being stored.

Enhanced by Zemanta

Interfacing The PHP World Would Be Good

With some precious free time today, I sat down to read Lukas Smith’s Interfacing The PHP World. It was good timing since last night I heard someone complain, again, about tight coupling in Zend Framework so I was in a good frame of mind to digest the blog post.

Before we start, tight coupling exists in a scenario where any one class relies upon another concrete class type (usually enforced using type hinting). Because the coupling is between two concrete classes, the only way to bypass it is through monkey patching the dependent class. Monkey patching has long been the lazy option for fixing stuff in PHP and we’re trying to get away from it. Loose coupling, on the other hand, exists when a class is dependent on an interface. Because we can write any class that adheres to that interface, we can inject any class we can imagine so long as it implements that interface. This is a far simple and maintainable situation since a) we are favouring composition over inheritance and b) there’s no fracking monkey patching!

The common denominator in loose coupling is therefore ensuring your dependent classes accept any dependency matching an agreed interface. Question: Whose interface are we agreeing on?

Every PHP framework has it’s own unique set of interfaces for common operations such as logging, caching, http clients, filtering, validation, etc. This creates a situation where a framework tends to be loosely coupled but only within the scope of its own interfaces. Thus, Symfony 2 components using HTTP can’t simply swap the existing client for Zend\Http\Client. Symfony 2 and Zend Framework 2 do not abide by an agreed interface – they have two distinct and incompatible ones.

Loose coupling is therefore a bad joke. It is a narrowly defined concept usually described within the scope of one particular application. We never really apply the concept across multiple applications written with different frameworks because, at that point, the disparate interfaces of both frameworks would immediately make loose coupling unobtainable.

That is the crux of Lukas’ idea – and it’s a really good idea. More interestingly, it’s almost an even better idea for Zend Framework 2 than Symfony 2. Zend Framework would benefit even more because we also distribute scores of component libraries and the interfaces relied upon make using Zend Framework components almost certainly contingent on the use of many other Zend Framework components to meet dependencies.

A simple example is Zend\Feed\Reader. For want of an agreed HTTP Client interface, we’re stuck with using…Zend\Http\Client. You could use Symfony 2′s client but then you’d need to create an abstract class to mediate between that client’s methods and the mismatched interface implemented by Zend\Http\Client. The result is therefore obvious – it requires more work and you’ll probably end up using both HTTP Clients rather than taking the hard road. Throw in a few more framework odds and ends, and you can be putting a lot of duplicated functionality to work just because they won’t speak the same language.

This is actually a bad deal for PHP programmers. Instead of one common interface for HTTP Clients, you have dozens. They won’t interoperate, they can’t be swapped for each other, and they directly encourage framework specific implementations instead of interface specific implementations (i.e. with common interfaces the need to duplicate functionality because of NIH Syndrome might be significantly reduced). You’re also forgetting those libraries who feel compelled to internally and eternally duplicate HTTP client functions rather than simply depending on a preferred client using a common interface. Not to mention half those mini-clients are poorly written and tend to disable SSL certificate verification because they can’t be arsed about handling the errors from invalid certs even if it does amount to putting your users’ private data at a real risk of being compromised.

The detractors from Lukas’ proposal may point to Java (since it’s the antithesis to everything PHP except the PHP OOP syntax :P ). While a worthy scapegoat, Java lives in a whole other environment. The scary Enterprise world. There, common interfaces are not merely programming conveniences but a business necessity. Competing products can gain a competitive advantage if they can replace a competitor’s product, service or middleware with a minimum of fuss. One way to help achieve that is to fund, support and advocate common interfaces for a variety of purposes. Not to mention it still benefits start ups since they already have the template for what to implement. It’s no wonder you see these debates stocked with members from competing companies actually cooperating so they have the future opportunity to back stab each other with one less barrier ;) .

Those detractors are not necessarily wrong either. On the web, history has favoured programming languages which are practical and flexible. PHP is an unstoppable force of nature for all that other language users criticise its sense of source code aesthetics. Ruby survives primarily because it has a popular framework built using the language. Javascript has proven invaluable for client side execution, and is even moving to the server side with developments like node.js. Python is, well, Python. How can you not like it (weird indentation aside)? Java, on the other hand, has declined in the web space and it’s sole remaining hope for a revival is greater adoption of the JVM for deploying the results of other languages boiled down into Java bytecode. Flexibility in setting interfaces would be important but that is a bit nonsensical when the adopters are frameworks who feel the competitive pressure to continually evolve…rapidly…and eek more sense out of PHP ugliness.

Then again, do I really want my baby, Zend\Feed\Reader, injected with Symfony 2 classes? It even sounds dirty. Filthy Symfony 2 classes (Zend Framework, my precious! Gollum! Gollum!). Yet, that’s the only real reason not to want common interfaces. By making your classes more accessible to the competitions’, you risk being commodotised as programmers mix and match from a selection of notable libraries instead of being hogtied to just a handful of sort-of-loosely coupled frameworks. Then again, HTTP Clients are already a dime a dozen. The real goal of competitiveness is having a better overall implementation in terms of features and all the other important stuff that meets the needs of the users you are targeting (this doesn’t include useless benchmarks though those do make a great butt for jokes).

So yes, common interfaces would benefit PHP and would make framework libraries more interoperable and thus usable within competing frameworks. Hey, if you can’t beat them at least make sure you can inject your classes into them. Hmm, still sounds dirty.

Enhanced by Zemanta