Monday, June 9, 2008

Securing cookies : a PHP implementation

Update: French version here.

Note for newcomers : you should first read the previous post introducing secure cookies : Security, Cookies and the REST.

So... where were we ? There is a secure protocol for cookies (see Alex X. Liu's paper for details) :

Cookie value =
username|expiration time|(data)k|HMAC(username|expiration time|data|SSL session key, k)
Where :
  • username is the username (or an unique identifier)
  • expiration time : the cookie's expiration time
  • (data)k is the result of a symmetric cryptographic (ex: Rijndael) function on data with key k.
  • data is the data you want to store in the cookie
  • k is the result of HMAC(username|expiration time, sk)
  • sk is the server's secret key
  • SSL session key is the SSL session key.

This protocol is secure :

  • It protects your cookie against replay attacks : SSL session key is unique to your SSL session. So a malicious user can't send the same cookie in another SSL session, it'll be invalid.
  • It protects the data confidentiality with a symmetric cryptographic function : data is stored encrypted
  • It protects the data integrity with an HMAC function
  • It protects your secret key against volume attacks

But it needs some flexibility for a common usage :

  1. SSL Feature is cool, it protects you against replay attacks, but :
    • Maybe you have no HTTPS access to your application
    • Cookie's lifetime is limited to the SSL session lifetime
  2. Data encryption is cool, but maybe you're not interested in this feature. If you are not, it expands the size of the cookie for nothing. For example: if data is encrypted with with Rijndael/256 bits key, the encrypted value will be at least 32 byte long, even if your data is 1 byte long

So, it may be cool to have a configurable class to manage secure cookies. By configurable, I mean to be able to :

  • enable/disable SSL feature
  • enable/disable the data encryption feature
  • choose the encryption algorithm

I've done a PHP class which have all these functionality. You can download it here.

Usage :

Initialization

include('BigOrNot_CookieManager.php');

$secretKey = 'Cei4Wai4ohcoo3daeHooFiek5Nah3Eet';
$manager = new BigOrNot_CookieManager($secretKey);

All you have to do is to provide a secret key. To generate a key you can use this shell command :

pgwen -sy 65

The default configuration is :

  • High confidentiality (data encryption) : enabled option name : high_confidentiality (bool)
  • Cipher : MCRYPT_RIJNDAEL_256 (Rijndael 256) option name : mcrypt_algorithm (see mcrypt documentation)
  • Mode : MCRYPT_MODE_CBC (CBC) option name : mcrypt_mode (see mcrypt_documentation)
  • SSL session key : disabled option name : enable_ssl (bool)

You can (optionally) give a second argument to the constructor to configure the class. For example, if you want to disable data encryption you can do that :

include('BigOrNot_CookieManager.php');

$secretKey = 'Cei4Wai4ohcoo3daeHooFiek5Nah3Eet';
$config = array('high_confidentiality' => false);
$manager = new BigOrNot_CookieManager($secretKey, $config);

Set a secure cookie

$expire = time() + 86400;
$value = $manager->setCookie('cookieName', 'value', 'username');
Read source for more details on possible arguments. (You can give all regular setcookie() arguments)

Read/verify a cookie value

$value = $manager->getCookieValue('cookieName');
If cookie is invalid, it will be deleted automatically. If you don't like this behaviour, you can give "false" as a second argument.

Delete a cookie

$manager->deleteCookie('cookieName');

Enjoy ! Source file is commented if you need more informations. If you have questions, remarks, bug reports, post a comment :)

Note: There is a class to use the same protocol with Django (Python) here.

13 comments:

perrick said...

Dommage que ce soit en anglais. Ce type d'article aurait sa place sur le "planete-php.fr".

Mat said...

Je vais voir pour faire une version du blog en francais :)

saladpope said...

I have read Liu's work, and was left with the impression that real-world implementation of this scheme was impractical due to the possibility that the client and server can at any time - effectively arbitrarily - opt to re-negotiate the SSL session and therefore change the key. Is this a real issue or is this a misapprehension on my part due to a (to say the least) less-than-perfect understanding of how SSL works?

Mat said...

I'm not a SSL expert but I agree with you : I think this is a real issue with the most common cases, because some browsers re-negotiate very often the SSL session.

In some particular cases you may require client certificates to access to your web application and use some informations coming from the certificate to be part of the securing cookie protocol.

Nesta said...

Hello,

Thanks for the code. I am validating against LDAP and using it to secure the password client side. However, there seems to be a bug.

The default path for setCookie is '' but the default for deleteCookie is '/'. When the default options for setCookie is used deleteCookie does not work with its default options. Changing the default path to '/' for setCookie fixed this for me.

Anonymous said...

Thanks for the code. I am validating against LDAP and using it to secure the password client side. However, there seems to be a bug...

viagra online said...

nice blog!

Cialis said...

Thank you for sharing this tutorial!

Unknown said...

The link to the source is broken =/

Mat said...

Thank you, it's fixed now.

Unknown said...

Thanks!

Anonymous said...

not working out of the box even after setting the default setCookie path has been changed to '/'.

Generic viagrabuy said...

Such a nice blog please keep posting such a things we are glad to share your blog and thanks for giving a place at your blog
Generic Viagra buy
Generic Viagra
Tadalis SX
Generic Viagra
Sildenafil citrate
Caverta
Kamagra
Online buy Generic Viagra

Lovegra