Securing Cookies: Mini Tutorial/Script

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
User avatar
nielsene
DevNet Resident
Posts: 1834
Joined: Fri Aug 16, 2002 8:57 am
Location: Watertown, MA

Securing Cookies: Mini Tutorial/Script

Post by nielsene »

As a spin-off from an earlier thread, I've been working out a php implementation of the suggestions made in Dos and Don'ts of Client Authentication on the Web

It features Message Authentication Codes(MACs) to protect the cookie data and expiration time as well as not trusting the user's browser to properly expire cookies.

This is close to a working infrastructure, I hope to clean it up with some comments from you, as well as integrate it with sessions to protect the sessionid in a good way.

Now the code: filename cookie.php

Code: Select all

<?php  
// this variables should live in your database configuration file, not here
$server_mac_secret = MD5("Some String, doesn't really matter what");  

// check if the user sent our cookie
if(isset($_COOKIEї'full_cookie']))  
{  
    // break up the cookie along its deliminators 
    $cookie_crumbs = explode('+',$_COOKIEї'full_cookie']); 
    $cookie_user_id =   $cookie_crumbsї1];  
    $cookie_expTime =   $cookie_crumbsї0];  
    $cookie_mac =       $cookie_crumbsї2];  

    // a debugging/reporting line to help you see what's going on, remove in real code
    $submessage = "User_id: $cookie_user_id<br />expTime: $cookie_expTime<br />MAC: $mac<br />\n";  

    // recalculate the MAC based on the values in the cookie
    $check_mac = MD5($cookie_expTime."+".$cookie_user_id."+".  
                     $server_mac_secret);  

    if($check_mac == $cookie_mac)  
    {  
        if (time() < $cookie_expTime)  
        {  
            $message = "good login";  
            // setup any variables you need, etc
        } else {  
            // redirect to a login screen
            $message = "expired login";  
        }  
    }  
    else  
    {  
        // handle attacks, probably destory the cookie, send email to you giving details
        $message = "tampered login<br />$cookie_mac<br />$check_mac";  
    }  
} else {  
// no cookie sent
// in a real program this should redirect to a login screen
// but for now we'll assume we had successfully logged a member in and
// set up the cookie
    $user_id = 14;  
    $expTime = time()+7200;  // cookie is good for two hours from login

    // create teh MAC to detect tampering
    // fields are joined together by a deliminator to prevent "slicing" attacks

    $mac = MD5($expTime."+".$user_id."+".$server_mac_secret);  

    // combine cookie data to a single variable, also using deliminators to allow exploding
    $full_cookie = $expTime."+".$user_id.'+'.$mac; 

    // we only need to send one cookie now 
    setcookie("full_cookie","$full_cookie",$expTime);  
    // debugging/ reporting data
    $message = "Set Cookie";  
    $submessage = "User_id: $user_id<br />expTime: $expTime<br />MAC: $mac<br />\n";  
}  
echo "<html><head><title>Cookie MD5 test</title></head>\n";  
echo "<body>\n";  
echo "<h1>$message</h1>\n";  
echo "$submessage";  
echo "<a href="cookie.php">Return to Page</a>\n";  
echo "</body></html>\n";  

?>
Notes: the cookie itself is still sent in plaintext across the network in this example, but any attempt to modify it will be detect. Tracking IPs will help avoid replay attacks, which I'll add shortly.

To turn this into an "autologin" type script, you would greatly extend the expTime. To increase the security you could shorten the expTime, but reset it on every connection. Ie, the cookie is good for say 15 minutes from the last access. When coupled with session, my next project, you'll have single session cookies, that are secure against replay attacks.
JPlush76
Forum Regular
Posts: 819
Joined: Thu Aug 01, 2002 5:42 pm
Location: Los Angeles, CA
Contact:

Post by JPlush76 »

I'm using this sample in my new ecommerce package I'm making, I'll put an example up later today :)
Coco
Forum Contributor
Posts: 339
Joined: Sat Sep 07, 2002 5:28 am
Location: Leeds, UK
Contact:

Post by Coco »

looks good... ill give it a spin, hopefully it will solve my session problems

*feels chuffed, actually understands the whole of that script*
User avatar
llimllib
Moderator
Posts: 466
Joined: Mon Jul 01, 2002 2:19 pm
Location: Baltimore, MD

Post by llimllib »

chuffed? is that british slang?

Oh, and script looks awesome...I may have to put it into service.
User avatar
Takuma
Forum Regular
Posts: 931
Joined: Sun Aug 04, 2002 10:24 am
Location: UK
Contact:

Post by Takuma »

I live in UK but never heard of chuffed... :lol:
Script is just amazing... I might implement to my website Thanks alot :D
JPlush76
Forum Regular
Posts: 819
Joined: Thu Aug 01, 2002 5:42 pm
Location: Los Angeles, CA
Contact:

Post by JPlush76 »

I put the script into my ecom site and it works like a dream except if I manually tamper with the cookie it doesn't let me access the page, but it doesn't give me the tamper msg either

other than that its a score holmes
Coco
Forum Contributor
Posts: 339
Joined: Sat Sep 07, 2002 5:28 am
Location: Leeds, UK
Contact:

Post by Coco »

chuffed = happy
User avatar
nielsene
DevNet Resident
Posts: 1834
Joined: Fri Aug 16, 2002 8:57 am
Location: Watertown, MA

Post by nielsene »

I'm glad people are finding this useful, I hope to have the next version out later this week. There will probably be two tracks: one for autologin systems and one for use with ephemeral session logins. I'm finidng that the two diverge enough to require seperate scripts instead of small customizations.

Anyone have any questions/concerns about the script that I should address whil working on it?
User avatar
nielsene
DevNet Resident
Posts: 1834
Joined: Fri Aug 16, 2002 8:57 am
Location: Watertown, MA

Post by nielsene »

New, Improved version availible at
http://ballroom-dev.mit.edu/compinabox/cookie.phps

This lacks the IP test, but can be used to protect the seesionid from tampering now as well as operating in several modes. You'll see a series of configureation values at the top of the file. For instance, an autologin script would probably use

Code: Select all

$usesSessions=TRUE;
$clientStoreCookie=TRUE;
$cookieDuration= 45 * 24 * 60 *60;//  (1.5 months)
$cookieExtend=TRUE;
$sslOnly=0;
$cookieData="user_id";
Under this approach the cookie will persist after the user closes the browser and will be valid for 45 days after the last visit. Alternative you could set teh cookieDuration much longer (such as 2 years) and then set cookieExtend to FALSE

A high security session site might use

Code: Select all

$usesSessions=TRUE;
$clientStoreCookie=FALSE;
$cookieDuration= 10 *60; // (10 minutes)
$cookieExtend=TRUE;
$sslOnly=1;
$cookieData=""; // defaults to session_id()
This site will detect attempts to change the id of the session in either the full_cookie cookie or in the session cookie sent by PHP. The users login lasts for 10 minutes since his last activity, so there is a minimal window for attack should the user not logout, when they leave the site. This is useful on a site where you expect short bursts of activity or long periods of sustained use. ClientStoreCookie is set to false to avoid the cookie being written to the clients disc for possible evil javascript re-exporting it to someone else.

Medium security session sites should problaby set the lifetime to about 8 hours and not extend the cookie.

I haven't tested all the paths through the code yet, but its typically working for me in different configurations. I'll add the options to enforce IP sameness next and then its probably done....
m3rajk
DevNet Resident
Posts: 1191
Joined: Mon Jun 02, 2003 3:37 pm

Post by m3rajk »

i take it you're a grad/doctoral student at mit?

it looks good. the reason i didn't use sessions is i don't know how to adjust the duration.

this looks much easier in setting duration.
User avatar
nielsene
DevNet Resident
Posts: 1834
Joined: Fri Aug 16, 2002 8:57 am
Location: Watertown, MA

Post by nielsene »

I was M.Eng student at MIT until last february. One of my friends wrote the linked article about proper use of authenticators (course I found it with a google search and didn't know he had done that...)

There's several things that should be done to the script. I'm hoping to get back to it some time. First I'ld like to library/class it up basically some sort of interface like, especially for use for securing regular sessions, but I'm in the middle of implementing a massive set of new features on my main application in order to gain a factor of 10 increase in user-base with an end of week deadline.
m3rajk
DevNet Resident
Posts: 1191
Joined: Mon Jun 02, 2003 3:37 pm

Post by m3rajk »

that's definitely a much higher priority.

but the mit thing explains a bit about security. i know a handful of people that went/go to mit. they're all freaks about security... i'd call them paranoid, then that'd be the kettle calling the pot...
User avatar
nielsene
DevNet Resident
Posts: 1834
Joined: Fri Aug 16, 2002 8:57 am
Location: Watertown, MA

Post by nielsene »

m3rajk wrote: but the mit thing explains a bit about security. i know a handful of people that went/go to mit. they're all freaks about security.
That comes from having Ron Rivest (the R or RSA) leading recitation section in the intro computer engineering course :)
m3rajk
DevNet Resident
Posts: 1191
Joined: Mon Jun 02, 2003 3:37 pm

Post by m3rajk »

lol. that explains it even better.
User avatar
wmasterj
Forum Commoner
Posts: 40
Joined: Mon Aug 18, 2003 5:52 pm
Location: Stockholm, Sweden

Post by wmasterj »

I just want to thank nielsene for sharing that script with us. It sure learned me alot. I'm not gonna read that article you friend wrote though... :) but thx!
Post Reply