I’ve seen several instances where people have demonstrated the ease with which encrypted cookies can replace sessions within PHP. Michael Nitschinger wrote a piece recently demonstrating the switch with Lithium, while CodeIgniter does this by default (optionally encrypting). The problem is that while replacing sessions with cookies works, it introduces a few risks not present with native session support, and these risks tend to be under documented.

Encryption is often viewed as a panacea for security problems, you sprinkle a little encryption dust around, and your problems dissolve. Unfortunately, while properly implemented encryption solves the problem of other people reading your encrypted data quite well, it doesn’t do much else. It doesn’t (on its own) tell you if other people have duplicated your data, manipulated the data in question, or handed you an old copy of properly encrypted data.

Consider an attacker who manages to sit in between Amazon and one of their warehouses. Amazon (in this theoretical example) encrypts all order instructions well, then transmits them to the warehouse. The warehouse decrypts the instruction, fills the order, and ships. If the attacker wanted free stuff they could place an order during a low traffic period, and wait for Amazon to send an encrypted message and make a copy. A few minutes later they could re-send that encrypted message to the warehouse, never having even tried to read it. With luck, they’ll soon receive two of whatever they just ordered! This is an instance of the replay attack, and that vulnerability is the one this post will examine in detail.

Exploiting cookie based sessions

Executing a replay attack against a cookie based session is easy, legitimately obtain some desired state on the system in question, and make a copy of your cookies. Should something go wrong, simply restore your cookies to the previous state. To demonstrate this, I’ve created a sample gambling application, you can get the source from github, or Play Now! (thanks to Orchestra.io, it's a free account so give it a moment)

In the game you start with $1000, then have the ability to make arbitrary wagers. Make a few bets to get a feel for the system, then make a copy of your cookie values. Bet again. If you lose money, simply restore your earlier cookies to get that money back. That’s it. This attack works because the system is willing to accept any successfully decrypted message as a valid, and current, session.

This attack doesn’t exist under traditional session storage. The user’s cookie doesn’t change from one request to the next as their money goes up and down. If a system is regenerating the session ID when the user changes privilege levels, the old session is deleted and no longer available when invoked properly: session_regenerate_id(TRUE);

A system using cookie based session storage, while using a CAPTCHA to defeat bots is doomed to fail, the attacker could solve the CAPTCHA once, then re-use that same cookie a million times. Encryption makes it difficult for an attacker to read the message, additional systems must be bolted on to defend against this sort of attack. In the stateless world of HTTP and the web, this is exceedingly difficult without some server-side datastore.

While this was clearly a trivial example, the problem is not. If you’re looking at using cookie based sessions it’s one of the things you need to be aware of.

If you’re interested in learning more about cryptography, including a great rundown of this problem and many others, I’d highly recommend Practical Cryptography


Take a look at this picture I took in the mall, in particular the Reitmans, Stokes, and Carleton Cards stores (left to right accordingly):

The stores look very different, mostly due to the colour of light they've used. In the Carleton Cards, there's a yellow light, adding a bit of warmth to a store built around relationships and expressing feelings. Stokes (a kitchen store) uses a very clean, white light, appropriate for clean kitchens, and pushing that meme. Reitmans (a clothing store) uses a rose coloured light which improves the look of skin for most people (especially us pasty Caucasians in the middle of winter).

Just another way stores are marketing to you that's easy to miss.


I get quite a bit of email, and deal with quite a few automated systems, banks, credit card companies, the cable company, etc. I’m tired of automated systems forcing me to ask myself a question to figure out what’s happening.

Here’s the first email I found with the word “if” in it:
We wanted to let you know that your order has shipped. If you ordered multiple items, you may receive separate shipments with no additional shipping charges.

My problem is that the email contains an “if”. There’s no reason for it. The computer that sent the email either does have access, or should have access, to my order. It knows that I only ordered a single product, so there’s no point in wasting my time with any other information.

My bank does something even more confusing:
A fee of $1.50 will be charged in the currency of the account for each cheque viewed. The fee will be debited from your account by the next business day. You may view a cheque as many times as you wish during your current EasyWeb session.
For personal chequing accounts the View Cheque service is free for customers who havePaperless or Online Only record keeping.

I have no idea what kind of account type I have. I push “Checking” to get money out of the ATM, but that doesn’t seem to be what it’s asking for. I opened this account when I was 16 years old, at a branch and bank that no longer exists. Do I have “Paperless” or “Online Only” record keeping? I’m not sure. Not knowing may cost me $1.50, but the computer running the bank most certainly knows what options I have on my account. That’s how it will know to charge me if I’ve got the wrong kind of account. Yet, I’m faced with the question.

Seeing these issues reminds me of an article I read back in 2004: Ten most persistent design bugs in particular “let you save me some time.”

In both these cases the developer decided to let me save him or her some time. They didn’t complicate their page or email template with an if structure, and instead presented one to me. Every Single person who interacts with that page, or gets that email is now forced to determine which case applies to them, all an effort to save some work on the part of one developer/designer some time ago.

It’s a stupid waste, and I wish it would stop.

I wish it was easy for me to persistently and privately tag an individual on the Internet with a keyword, then hopefully a short justification. When reading an interesting blog post or tweet you could tag them as interesting or understands cryptography or the like. Then the next time you ran into a post, comment, tweet, conference schedule, whatever from that individual that tag would be visible.

It could in theory live almost entirely in the browser, but I think it would work best with some sort of centralized backend to facilitate cross device consistency.

It doesn’t need to be perfect, nor does it need to pierce any sort of attempt at anonymity. Think about gravatar, a great service that plugs your picture into blog comments through your email address. It’s neither perfect nor completely pervasive but it’s still helpful.

To be clear this isn’t something I want to add onto Facebook or Twitter. I’m not friends with these people, I don’t need to hear when they’re drunk, dating, or farming pixels. Nor do I want to read every inane comment or checkin they push to Twitter. I’d simply like a little icon to appear the next time I encounter them on any medium letting me know they’re brilliant, or a racist bigot so I can react appropriately…

Apart from the (hopefully) apparent utility, I also think this helps bring us back something we’ve lost. One hundred years ago if someone said something interesting to you they were standing in front of you (or at least within earshot) and you’d likely have an easy time remembering that individual to credit them later, or simply pay extra attention that individual attempted to share a remark. By the same token if someone said something idiotic and offensive you’d have an easy time remembering them, and simply walk to the other side of the bar when they mount their soap box. We’re exposed to opinions from nearly faceless individuals at a terrifying rate these days, and along the way lost the ability to appropriately credit the things we’ve seen, this wish would make serious progress to fix that.


I fell in love with Hooks in frameworks recently; the honeymoon period was tragically short.

First, the love story:

I ran into hooks rather simultaneously with two very different frameworks: Code Igniter and Lithium. In both cases I was using a rather nifty hook to handle ensuring that users were properly authenticated and authorized before accessing a page. I think we can all agree having to add some code to every single method is foolhardy: if (!isset($_SESSION['user_level']) OR ($_SESSION['user_level'] != 'admin')) { header('Location: ' . APP_ROOT_URI); exit; }

Hooks provide a great way to solve the issue. Within Lithium you can leverage the filters mechanism to handle authentication quite easily, in fact it's an example case in their tutorials. The beautiful thing about it in my mind is the simplicity of things at the controller level: I simply list the publicly accessible methods in a property (public $publicActions = array('login');), and everything else is assumed to only be accessible to logged in users. Fantastic! If I mess up when adding a new method, it defaults to closed, which is exactly the result I'm looking for.

Over with Code Igniter things are really quite similar. The post_controller_constructor hook can be used to invoke a specific class and controller. That class can return true, redirect a user, whatever as appropriate. Since it's invoked after the controller is instantiated, similar configuration options can be made available.

The honeymoon

I ripped redundant, error prone, easy to forget, and fundamentally stupid checks out of all of the controllers where I'd added them. These new systems were much easier to maintain, required a lot less code, and I didn't need to add 10 lines of unrelated bloat into each controller. Life was grand. Days where I wrote negative lines of code felt glorious.

The big fight

One day, while messing around, I accidentally turned off the hook configuration within Code Igniter (actually I clobbered a file, and restored the wrong one). Then, things came crashing down in a horrible cacophony of... actually they didn't. Everything kept working: that was the problem. The entirety of my security system was turned off because one file was wrong, and things kept working. Sure, specific calls that referenced the current user's username broke, but there was more than enough left vulnerable for me to get a big chill.

Counselling

Revisiting the hooks system, I was shocked by the tremendous lack of depth in my defense: one mis-configured file and security was off. Even worse, nothing broke. There was no evidence that the security was disabled unless you went probing, which is horrible. The only thing worse than a safe that won't lock, is one that looks like it's locked but pulls open to a slight touch.

Conciliation

The easy thing to reach for with both Lithium, and Code Igniter is __construct(). A single, unified location to ensure that the authorization tests have been executed. Unfortunately, in both cases __construct() is called long before the authorization hooks are run. More specialized solutions are required.

With Lithium

The __invoke() method is invoked after the authorization filter, so it's a great candidate for double checking. public function __invoke($request, $dispatchParams, array $options = array()) { if (!defined('AUTH_CHECKED')) { throw new DispatchException('Authorization filter not run.'); } return parent::__invoke($request, $dispatchParams, $options); }

With Code Igniter

The _remap() function is called (when available) to allow you to remap incoming requests to a different method. Since it's invoked universally, the check can go there. public function _remap($method) { if(defined('AUTH_CHECKED')) { $this->$method(); }else { exit('ACL Configuration Error'); } }

Both of these cases provided me with the depth I was looking for. I'm no longer entirely dependent on one configuration option or file for my security to function. Should it fail, I've got a secondary check in place; this example of defence in depth allows me to be comfortable with the hooks security system once more.

Final thoughts

Through researching this, and exploring several code bases to which I have access, I've noticed two distinct strategies for managing method level access. In Lithium, each class indicates which methods should be accessible to which security groups using a public property; by contrast, in the other strategy, public methods were explicitly laid out inside the single authorization function. The former has the advantage of allowing you to quickly and easily manage security while you add functions to a given controller; the latter solves the issue of your authorization rules being scattered across each and every controller by centralizing them in one easy to locate file.

Updates!

Some suggestions have cropped up:

  • Unit Testing
  • While I'll agree that great, properly implemented, unit testing would have caught this it still doesn't leave me feeling comfortable. First, I've seen a lot of unit testing code, and much of it wouldn't have caught this. Either because the code specifically tested the authentication, and authorization code on its own, not combined with the actual controllers. Or because it used its own configuration file during testing, missing the fact that something had been removed from production. Second, I'm not sure that simply exposing the issue with unit testing would make me comfortable, I definitely would have caught it faster. Possibly even as soon as I'd committed the code. But I'd still like something running along side the code constantly to make sure the checks are in place.
  • Auth Specific Class
  • As suggested by Chris Morrell (in this series of tweets) I could be using a dedicated authorization class. While this does solve the configuration problem by calling it explicitly, I'm losing granularity or making a call with every action. I'll lose granularity if I decide to put one initial call in my constructor (or other early globally called method) since it affects the entire class. Ending up making a call with every action was exactly what I was trying to avoid in the first place. That said, the use of getIdentity() vs requireIdentity() is quite slick, I like how simultaneously explicit and transparent a normal action becomes.


This is the first in a continuing series of things I wish. Posted on Wednesdays

"This doesn't sound hard"

All I want is a DVD ripper that can do what a CD ripper did over a decade ago. I'd like to insert a DVD into my computer, have it look up the meta data on some sort of modern CDDB equivalent, then rip the disk with appropriate meta data for iTunes. It will need to understand the difference between Television and Movies, as well as how to rip the right audio track, and what chapters are associated with what episode. This really doesn't seem that hard. Yet, I don't have one. Everything I've seen requires me to figure out those associations, or handles meta data poorly.

RipIt: Is a functional ripping tool, it however doesn't seem to understand TV disks. I put in Battlestar Galactica Season 1, Disk 2. It ripped it into a single file, that turned out to be something like the middle of episode 3 to the end of episode 4.

Handbrake: Another functional ripping tool, it requires me to figure out which chapters are associated with which episodes on a disc. I don't want to worry about this, put a disc in, wait, take disk out, repeat.


I'm on a mac, though if something truly perfect came out for Linux or Windows I'd rip from a VM.

Hi, I’m Paul Reinheimer, a developer working on the web.

I co-founded WonderProxy which provides access to over 200 proxies around the world to enable testing of geoip sensitive applications. We've since expanded to offer more granular tooling through Where's it Up

My hobbies are cycling, photography, travel, and engaging Allison Moore in intelligent discourse. I frequently write about PHP and other related technologies.

Search