Welcome to my site

Post statistics

Cookie replay attack protection

Following on my previous security article on Defensive Programming I’ll be talking you through and providing a sample class to protect against replay attacks. Internet security is not one to be taken lightly. There is a saying that Internet Security is a trade-off between security and usability. And that’s true for the most part, but luckily protection against replay attacks does not hinder usability—it’s almost completely transparent to the end users.

So let’s jump straight in, what is a replay attack? Essentially a security breach whereby someone poses as someone else using some unique piece of data the user supplied/was issued to/from the Web server. It’s kind of similar to a man-in-the-middle attack. We’re going to be looking at the attack using specifically cookie authorisation, a very common means of implementing a “remember me” function.

Replay attacks are often one thing that programmers forget to protect against. This really is quite a worry since I want my identity to be safe online and I’m sure you do, too. Let’s look at the problem in a readable form:

  1. John logs into example.org.
  2. Server issues John a cookie with value of 12345.
  3. John revisits example.org again and is logged in.
  4. Evil Joe looked at the request and steals the cookie.
  5. Joe visits example.org which logs him in as John.

Due to the very nature of the attack it isn’t possible to 100% protect against it, it’s inherently insecure. But there are ways to increase the security, and that’s to add another step after (3) above:

  1. Server reissues John a cookie with value of 67891.

It’s called token regeneration. We have recognised that John has a valid cookie, logged the user in, removed their old cookie and recreate a new one that no one else should know. Even if Joe had the old cookie it’s no longer valid and has to perform the same actions as (4) in the original way.

Another method is to add some kind of time restriction, so only make the cookie valid for a certain amount of days. So if Joe happens to stumble across the cookie after a month he should no longer be able to login as John. Another to add in which browser John is using, the chances of John using exactly the same as Joe is unlikely. But again it is possible, so don’t rely on it!

Firstly we will need another table into our database (I’m going to assume you have a semi-advanced knowledge of databases and PHP), I’ll call it login_token.

With that in place, let’s create a couple of small PHP class to do the remembering. I’ll start with a nice cookie class
so our remembering function is a little neater (Remember, we want high cohesion and low coupling!).

<?php
class Cookie
{
    /**
     * Sets a cookie via pre-set parameters.
     *
     * $expires is the number of days to keep the cookie alive.
     *
     * @static
     * @param string $name
     * @param string $value
     * @param integer $expires
     */
    public static function save($name, $value, $expires) {
        setcookie($name, $value, ($expires * (3600 * 24)), '/', false);
    }
 
    /**
     * Returns a cookie through the name
     *
     * @static
     * @param string $name
     */
    public static function get($name) {
        return isset($_COOKIE[$name])
            ? $_COOKIE[$name]
            : '';
    }
 
    /**
     * Deletes the cookie.
     *
     * @static
     * @param string $name
     */
    public static function delete($name) {
        setcookie($name, '', (time() - 3600));
    }
}

Now we’ll create our actual remembering class:

<?php
class RememberMe
{
    /**
     * See if the user has a login for this site.
     *
     * <ul>
     *      <li>Does the auth cookie exist?</li>
     *      <li>Does the auth cookie look correct?</li>
     *      <li>Can we find the auth cookie in the datbase?</li>
     * </ul>
     *
     * @return boolean
     */
    public function attemptRememberMeLogin() {
        // Does the cookie exist?
        if (isset($_COOKIE['auth'])) {
            // Does it have a correct MD5 hash length?
            if (strlen($_COOKIE['auth']) == 32) {
                // Does the cookie exist in the database?
                $query = mysql_query("
                    SELECT  `user_id`
                    FROM    `login_token`
                    WHERE   `login_value`     = '" . mysql_real_escape_string($_COOKIE['auth']) . "'
                    LIMIT   1
                ");
 
                // Cookie found?
                if (mysql_num_rows($query) >= 1) {
                    // Get the data
                    $data = mysql_fetch_assoc($query);
 
                    // Reset the cookie
                    $this->remember($data['user_id']);
 
                    // Return that the user has successfully logged in via a remember me cookie
                    return true;
                }
            }
 
            // User has a cookie, but it is invalid
            Cookie::delete('auth');
        }
 
        return false;
    }
 
    /**
     * Set the remember me cookie.
     *
     * <ul>
     *      <li>Firstly remove all the past cookies they may have had.</li>
     *      <li>Generate the new MD5 cookie.</li>
     *      <li>Create the cookie on users computer.</li>
     *      <li>Insert the cookie into the database.</li>
     * </ul>
     *
     * @param int $userId
     */
    public function remember($userId) {
        // Remove the old cookies
        // Client cookie
        Cookie::delete('auth');
 
        // Database cookie
        mysql_query("
            DELETE FROM `login_token`
            WHERE       `user_id`   = " . (int)$userId . "
        ");
 
        // Create the new cookies
        // Client cookie
        $cookie = md5($userId . $_SERVER['REQUEST_TIME']);
        Cookie::save('auth', $cookie, 7);
 
        // Database cookie
        mysql_query("
            INSERT INTO `login_token`
                (`user_id`, `token_value`, `token_valid`)
            VALUES
                (   " . (int)$userId . ",
                    '" . mysql_real_escape_string($cookie) . "',
                    " . ($_SERVER['REQUEST_TIME'] + (7 * (3600 * 24))) . "
                )
        ");
    }
}

And there we go. We have successfully written an almost secure way to implement a “remember me” function. Of course you can take this further by adding even more security, such as:

  • Prepared SQL statements.
  • Add the user agent to the database (You expect returning visitors to use the same browser, if not then they will need to login again anyway (unless they upgrade their browser, but this is infrequent!))
  • Store the user ID in the cookie to reduce hash collisions.
  • And a myriad of other ways.
Date posted August 24th, 2009
Comments Disabled
Categories PHP
Author Christopher Hill

I'm Christopher. A twenty-something graduate, star gazer, aspiring triathlete, vegetarian, reader and writer, cinemaniac and lover of life in general

From the journal

From the deep

Obligatory links

Create simple UML diagrams on-the-fly

yUML is an online tool for creating and publishing simple UML diagrams. It’s makes it really easy for you to: Embed UML diagrams in blogs, emails and wikis, Post UML diagrams in forums and blog comments, Use directly within your web based bug tracking tool and Copy and paste UML diagrams into MS Word documents and Powerpoint presentations.

Javascript Tidy

One thing I often need to do is to tidy javascript from it’s packed state. Often to fix the developers bugs, add new features or to modify it slightly. I give you, the Javascript Tidy, a tool I couldn’t live without.

jQuery Slider plugin (Safari style)

A pretty awesome slider. Haven’t tried it out yet but the new version seems pretty easy to skin, so you can style it however-the-hell you want (note: click the ‘jQuery Slider update’ link).

MySQL Format Date

MySQL Format Date helps you format your dates using the MySQL DATE_FORMAT function. Just select a common date format and then change it to your suit your needs. The MySQL DATE_FORMAT code will be generated at the bottom of the page which you can then copy into your query.

The future of wireframes?

I have a love hate relationship with wireframes. In the last 10 years they’ve been a part of every web project I’ve worked on. There have been times when I can’t imagine how we would have solved a particular problem without them. Yet there are also times when I’ve been completely exasperated at the amount of time and energy they’ve consumed, seemingly to very little reward.

So you need a typeface?

A pretty humorous look into how you could choose your typeface for your next project.

New global visual language for BBC

We decided to embark on an ambitious project, called Global Visual Language 2.0, with the aim of unifying the visual and interaction design of bbc.co.uk and the mobile website.

jQuery plugin: Nivo Slider

A really cool image slider than has some unique transitional effects without using Flash.

MooTools plugin: DatePicker

jQuery has the best functioning plugins. MooTools has the best looking plugins. Whenever I want to add in a datepicker I always find this and think: “Oooh. Pretty. Do want.”. Then realise it’s MooTools only. Real shame.

jQuery plugin: Sparklines

I know, I know. This plugin has been around for, what seems like, years. But I thought I would give it a little bit of a spotlight. And yes, so I can easily find it again.

jQuery plugin: asmSelect

asmSelect is a jQuery plugin providing progressive enhancement to select multiple form elements. It provides a simpler alternative with several advantages. This new version includes several bug fixes and enhancements.

How coupon codes can lead to lost revenue

In this post we’ll be looking at how coupon codes (used synonymously here with promo and discount codes) can cause retailers to lose revenue. I’ll share some (hopefully) interesting trends that I’m seeing with a client I work with, and hopefully start a discussion with how to turn lost revenue into gained revenue.

A good browser should be able to reproduce itself

This is an interesting project which aimes to completely reproduce the visual aspect of Safari in pure HTML+CSS with zero images. There are a few caveats at the moment, such as no refresh button, but they say they are working on it. Once again this really shows the power that HTML5 and CSS3 brings to the Web.

jQuery plugin: gameQuery

gameQuery is a jQuery plug-in to help make javascript game development easier by adding some simple game-related classes. It’s still in an early stage of development and may change a lot in future versions.

CSS/Javascript Word Clock

A lit­tle ex­per­i­ment I built: a word clock using CSS3 trans­forms and a lit­tle Javascript to run the ac­tu­al clock. Use­ful? Maybe not. Fun? Def­i­nite­ly.

CSS Border Radius Web Page

It’s one of those things that makes you think “Doh! I should have made that agaes ago”. A simple Web page that allows you to simply get the CSS for the exact border radius you want.

The main thing is not to install Flash

A security expert who has won the Pwn2Own contest for 2 years running said, basically, that Flash is insecure. Well, we all knew that which is why we add Flashblock and the like. Right?

Pure CSS3 Bokeh effect

One of the best apps made using CSS3, that’s for sure. A few more options would be nice, such as changing colours of the circles and being able to place them manually.

EZ-CSS: An easy to use, lightweight, CSS framework

It is light (1kb), flexible, browser-friendly and easy to use! ez-css is a different kind of CSS framework. Authors are not bound to a “grid”. Plus, columns and gutters can be of any width.

jQuery plugin: Quicksand

I love Mac apps, especially for their attention to detail. CoreAnimation makes it so easy to create useful and eye-pleasing effects. Quicksand aims at providing a similar experience for users on the web.