LearnHow to Create Totally Secure Cookies

Robert Hafner
writes on August 24, 2009

Share with your friends


Securing cookies and sessions is vital to keeping an application secure. Many tutorials have been written on the subject, but as the internet (and browsers loading it) evolve so do the methods you can use to keep your application secure.

In this article we’re going to break down the various components of a cookie and what they mean for security. This will include limiting the cookie to certain domains and paths on those domains, choosing what information to store, and protecting the cookie from cross site scripting exploits. In a second article we will go into more depth in how to protect everyone’s favorite cookie, the session ID.

How Cookies Work

Cookies are simply key/value pairs that let us get around HTTP being a stateless protocol. When a developer has data they wish to last for more than one connection they can use cookies to store that data on the client side. While this tends to get handled by the programming language being used it is accomplished using HTTP headers.

When the server wants to set a cookie it passes back a header named “Set-Cookie” with the key-value pair and some options.

On subsequent requests the client will send along its own header to let the server know the name and value of its stored cookies. The server will not continue to send back the cookies, it will only send them if there is a change.

You can see all the headers for yourself using the LiveHeaders plugin for Firefox.

The Problem

This data is completely in control of the client- it is trivial to change the values of a cookie. That means that, just like post and get data, all cookie data must be validated in some way. At the same time you’ll want to avoid storing sensitive information, such as passwords, as cookies are stored in cleartext and anyone with access to the computer later can easily pick those up (I know of at least one security forum that was hacked in this way). It is also important to note that HTTP does not encrypt the headers in any way. If the connection isn’t over SSL then it will not be protected from snooping eyes.

Session cookies are no different than any other cookie- their value is just a simple ID. Those IDs are susceptible to all of the same limitations as other cookies. The real power behind sessions happens server side, where the ID is used to pull out data stored on the server. This has many benefits over storing data directly into the cookie itself- data can’t be manipulated by the user, large amount of data can be stored without having to send it back and forth with each request, and you can store data you otherwise wouldn’t want the client to have access to.

Getting Started

The first step towards securing your cookie is to restrict that cookie to only your application. This is especially important in environments that support multiple sites or applications (the type of shared hosting you often see on corporate or university domains). By restricting the cookie to only the applications that need it you reduce the chances of it being sniffed while also keeping the cookie namespaces clear for other applications that use them.

There are three options that can be sent along when creating a cookie that, when used properly, will keep the cookie limited to only your application. Before setting these options you will need to ask yourself a few questions-

  • What parts of the website need access to the cookie?
  • Will the cookie need to work across sub domains?
  • Will the cookie need to persist if the user leaves an SSL portion of the site?

There is also a forth option used by newer browsers to restrict access to cookies by javascript.

As you will see, how exactly to restrict the cookie really does depend on the exact purpose for that cookie. A banking or ecommerce site may restrict their cookies to only SSL, while a blog or news aggregator may want to leave things more open.

Cookie Options

Send The Cookie To Only Your Application

The Path argument specifies what paths on the site to send the cookie. The default value of “/” means every request will get the cookie, while “/forums/” would limit the cookie to just that path. This path is going to be based on the actual URL the browser uses, before any mod_rewrite or other URL mapping.

Don’t Share With Sub Domains

The Domain option allows you to specify whether or not to send the cookie to subdomains. Setting “www.example.com” will mean only the exact domain “www.example.com” will be matched, while “.example.com” will also match again any subdomaim (forums.example.com, blog.example.com).

Require a Secure Connection

Using the Secure option you can tell the browser (or other http clients) to only send the cookie over SSL connections. This means the cookie will not be available to any part of the site that is not secure will not have access to the cookie, but it also makes it much less likely that you’ll accidentally send the cookie across as cleartext.

Protect Against XSS Exploits

This HttpOnly flag is used to tell the browser that it should not allow javascript to access the contents of the cookie. This is primarily a defense against cross site scripting, as it will prevent hackers from being able to retrieve and use the session through such an attack.

The HttpOnly option is not by any means full proof. As a client-side defense mechanism it relies on browser support to work, but is only supported by a few browsers (Firefox 3+ and IE 7+, with partial support from Opera 9.5, IE6 and Chrome).

Configuring the Cookie

In PHP, setting the arguments for cookies is done through some optional arguments on the “setcookie” function:

setcookie( name, value, expire, path, domain, secure, httponly);

// Open
setcookie( 'UserName', 'Bob', 0, '/', '.example', false, false);

// Locked Down
setcookie( 'UserName', 'Bob', 0, '/forums', 'www.example.com', isset($_SERVER["HTTPS"]), true);

To change the cookie values for the session cookie requires the “session_set_cookie_params” function, which needs to be called before the session is started.

session_set_cookie_params($expire, $path, $domain, $secure, true);

// Open
session_set_cookie_params(0, '/', '.example', false, false);

// Locked Down
session_set_cookie_params('o, /forums', 'www.example.com', isset($_SERVER["HTTPS"]), true)


Cookies remain the basic method of identify tracking on most websites and keeping them secure is a vital part to keeping applications as a whole locked down and secure. In this article we went over four methods for protecting cookies on a general level.

When using cookies its important to remember to:

  • Limit the amount of sensitive information stored in the cookie.
  • Limit the subdomains and paths to prevent interception by another application.
  • Enforce SSL so the cookie isn’t sent in cleartext.
  • Make the cookie HttpOnly so its not accessible to javascript.

Please check out the second half of this series, where we’re going to take the next step with an in depth guide to securing sessions.

46 Responses to “How to Create Totally Secure Cookies”

  1. Great explanation of cookies and cookie properties. In the example security largely depends on enforcing SSL. But SSL only works on HTTPS, right? What about situations where HTTPS isn’t possible? What’s your take on encrypting cookie data?

  2. Using session cookies therefore should always be preferred over “normal” cookies. To secure session cookies, you can bind the session_id() to the unique combination of User_Agent and Remote_IP. Session hijacking can also be prevented by changing the session_id() of a session (using session_regenerate_id()) on a regular basis.

    • Ryan Carson on August 24, 2009 at 9:30 am said:

      Thanks Philipp. Just an FYI, Robert has written another article about specifically securing Sessions. Should go live in a few weeks.

    • About binding the session_id() to the unique combination of User_Agent and Remote_IP.
      In large organisations, chances are that many users will share the same IP as internet access is regulated. I also use session regeneration, but I wonder if session regeneration wouldn’t be defeated by enterprise caching (but that’s another story).

    • Jean Marie on September 2, 2009 at 2:23 pm said:


      using the users remote IP is a bad idea because many users sit behind a NAT-Gateway.

      Best regards
      Jean Marie

  3. A good reminder about the main properties to work with cookies offering good security levels.
    I think what’s interesting is what is actually saved in the cookies as this is a common mistake that beginner developers do: save directly sensitive information.

  4. Great Article! Very Important! thanks for the tips!

  5. I’m not usually much of a critic, but I was quite disappointed with that article. For one thing – you only mentioned the very basics of how cookies worked and left it at that, you briefly flew over encryption and you didn’t even mention anything that the programmer can do at an application level, such as signing.

    I find signing cookies a great way to secure any data you put in a cookie. In fact, authentication systems work great if you just chuck the user ID in a cookie and then sign the cookie to stop anyone tampering with it.

    For these examples I’ll be using PHP, but the ideas are pretty simple to implement in other languages. The trick is is to make an hash (I use SHA1) of all the data, along with an application-level secret key. I also add a random hash for good measure. Then encode it in base64 and save it to the cookie.

    define(SECRET, "frg354gifhfweufnv8r9rwe0fs9duvsnitjeityuw8fywjrek");
    // ...

    $user_id = $id;
    $hash = sha1(rand(0,500).microtime().SECRET);
    $signature = sha1(SECRET . $hash . $user_id);

    $cookie = base64_encode($signature . "-" . $hash . "-" . $user_id);
    setcookie('authentication', $cookie);

    To then get data from the cookie you simply decode it, split it by the “-” character, check the hash and return the data.

    $data = explode('-', base64_decode($_COOKIE['authentication']));

    if ($data[0] !== sha1(SECRET . $data[1] . $data[2])) {
    die('You tampered with your cookie!');
    } else {
    //All good! Do whatever here...

    I hope this has helped – I liked the premise of this article but it didn’t take long to go into a bit more detail about how you can do something like this.


    • “I was quite disappointed with that article. For one thing – you only mentioned the very basics of how cookies worked and left it at that”

      Agree. This is old school magazine style writing to get you to buy the next issue and keep coming back. In this case, it will be “a few weeks” to get more information, and not necessarily all of it.

      It’s very irritating. The article is fragmented making it mostly useless until complete. Carson, let me know when it is complete. Then I’ll read the whole thing. Unless I Google this and find the answers on other sites.

      • My point wasn’t to try to get people to come back and read more later, its just that the cookie itself is a small part of the session. The next article focused on sessions, and uses a lot of example code, so by the time it was done it seemed big enough to stand on its own (its much longer than this post, for instance).

        I definitely understand what you’re saying though, and will keep it in mind for future posts (I am still rather new at this).

    • Signing cookies indeed is a good idea. The cookie helper of the Kohana PHP5 framework uses a very similar technique. Very clean code and well commented, good to learn from: Kohana_Cookie class.

    • This technique has merit, but there are a few things to consider-

      * If you’re primarily using the data server side, it would be better to simply store it in a session. Otherwise, while you’re protected from tampering you’re still open to sniffing of sensitive data and hijacking of cookies.

      * Tying it to the user id only helps so much, as the user id won’t be present until the session is already loaded. This would, from the perspective of the hackers, just make the hash another session id. If they can steal the session (and take on the user ID) they’ll be able to steal the other cookies as well.

      * If someone logs out all of their cookies are invalidated- this may be intentional, but if you want data tied to a session it should be in the session.

      * If you’re using the data client side (javascript) you’re only going to have read only access.

      That being said, I really should have touched on this subject, as there are definite cases where it would be useful. Thank you for fixing that discrepancy on my part.

  6. You shouldn’t store sensitive information in cookies. Store the bare minimum, and implement tampering detection like kari or jamie mentions.
    Alternatively use an ID and a checksum and store it in a database… E.g.

    // To “encode”
    $id = 232; // ID to a database record, for instance
    $my_secret = md5( “Some secret, eh?” );
    $checksum = md5( md5( $id ) . $my_secret );

    // To decode:
    list( $id, $checksum ) = explode( “-“, $_COOKIE[‘the_cookie’] );
    $my_secret = md5( “Some secret, eh?” );
    if ( md5( md5( $id ) . $my_secret ) != $checksum )
    die( “Tampering detected” );

    In the database you can store whatever you want.

  7. I believe Safari 4 also supports HttpOnly on cookies. Finally.

  8. Great explanation of what are cookies, thanks for sharing.

  9. My kids loves cookies and so are we. Thanks for the tips, my wife would be very glad to know this. :)

  10. The holidays are finished and so is a freshly made jar of those cookies, nice job:)

  11. Nice Information about cookies,

    thanks a lot :-)

  12. hello admin, I found your blog from yahoo and read a few of your other posts.They are awesome. Please keep it up!!
    copy xbox 360 games

  13. There were quite a few hacks and sneaky tips that I didn’t know about. Thanks

  14. Michael J on June 11, 2010 at 11:59 pm said:

    In your example you used isset($_SERVER[“HTTPS”]) to ensure that cookies will only be sent when it is over an HTTPS connection. This will however not work as the this will just except the current setting. Let me explain. If I access the page via HTTP the value for this expression would be false, telling the browser to send cookies over HTTP and when accessed via HTTPS the expression would be true, thus sending cookies over the secure connection.
    For HTTP the expression
    setcookie( ‘UserName’, ‘Bob’, 0, ‘/forums’, ‘www.example.com’, isset($_SERVER[“HTTPS”]), true);
    would result to
    setcookie( ‘UserName’, ‘Bob’, 0, ‘/forums’, ‘www.example.com’,false, true);
    and for HTTPS
    setcookie( ‘UserName’, ‘Bob’, 0, ‘/forums’, ‘www.example.com’,true, true);

  15. Your articale is really informative, but a little profound to me.

  16. Is this line correct? >>

    session_set_cookie_params(‘o, /forums’, ‘www.example.com’, isset($_SERVER[“HTTPS”]), true)

  17. Good article. You might consider getting more in-depth on the server side aspect of sessions. Like how to store session data outside memory so you can run in a load balanced environment. Also, please consider not floating the social media toolbar at the top of the window the whole time. A bit annoying.

  18. This article is very useful for me because I am a new beginner for PC and do not know anything about the word” cookie”. Now I can use secure cookie and that make me happy.

  19. This article is very useful for me because I am a new beginner for PC and do not know anything about the word” cookie”. Now I can use secure cookie and that make me happy. http://www.mac-ipad-converter.org/

Leave a Reply

Learn to code with Treehouse

Start your 14 day free trial today and get access to hundreds of video courses in web development, design and business!

Learn more