Skip to content

Storing Data Client Side

There are several ways that browsers can let us store data on a users computer.
This lets us store information about the user, such as their preferences locally without needing a full database at the back-end.

This information can be used to help a dynamic website (i.e. one that is build using technologies such as JavaScript) to apply the users preferences, or to store information that will be needed for later requests.

In this article we take a look at the most common methods of storing data locally.

Cookies

The "Traditional" method of storing user information, a Cookie is a small piece of information associated with a domain, that is forwarded to the server each time a request is made.

The original cookies were designed to help deal with the stateless nature of HTTP. As the HTTP protocol has no way of linking different requests, this made implementing things like shopping carts (or even logins) difficult.

Cookies are now predominantly used for:

  • Session Management: Logins, shopping etc.
  • Tracking: Recording user behaviour
  • Personalisation while cookies are being superseded by technologies such as local storage. They can still be used for storing user preferences.

First and Third Party Cookies

Cookies may be sent to sites other than the one you are currently visiting.

  • First Party Cookies are that match the domain of the current site (the web address in the tool bar)
  • Third Party Cookies can be sent to sites outside of the current domain.

Lets say we embed a player from YouTube or similar in the page. This may come with a cookie attacked that records the users preference when it comes to YouTube. This could cause problems with things like CSRF (Cross Site Request Forgery) attackers, where a 3rd party site requests a users cookies.

Setting and Sending Cookies

Cookies are set (or stored) on the client machine using the Set-Cookie HTTP Header.

Set-Cookie: <Cookie-Name>=<Cookie-Value>

Example

For example, a server could ask the browser to set the storedData cookie to cookieValue by sending the following Response Header

HTTP/2.0 200 OK
Content-Type: text/html
Set-Cookie: storedData=cookieValue

When setting cookes, we need to specify each cookie, and any of its parameters as a newline in the response. For example to set both a storedData and sessionID cookie the response headers would be.

HTTP/2.0 200 OK
Content-Type: text/html
Set-Cookie: storedData=cookieValue
Set-Cookie: sessionID=BLEH

Once a cookie has been set, a user-agent will transmit it as part of all requests to the given resource, using the Cookie Header.

Example

Given the example above, our Browser would forward the stoored cookie in any further requests using the following headers

GET /page.html HTTP/1.1
Host: www.example.org
Cookie: storedData=cookieValue

Multiple cookies are transmitted by seperating them with a semicolon

GET /page.html HTTP/1.1
Host: www.example.org
Cookie: storedData=cookieValue; secondCookie=secondValue

If the host wants the browser to set other cookie parameters (such as expiry date) these options are appended to the Set-Cookie header.

Example

For example, if the host wanted to set an expirey date (see below) the following header would be sent as part of the response

HTTP/2.0 200 OK
Content-Type: text/html
Set-Cookie: storedData=cookieValue; Expires=Thu, 31 Oct 2021 07:28:00 GMT;

The Cookie-Name field, sets the name of the cookie that is stored by the browser, for example when using PHP based sessions the cookie will be called PHPSESSID

The Cookie-Value field defines the data stored in the cookie. In the case of a PHP based session, this will be the unique identifier representing the session on the server.

When setting a cookie, we also have options for the cookie lifetime.

  • Session cookies should expire at the end of a browser session (IE when the user closes the browser window). This is the default condition when no cookie lifetime is set
  • Persistent cookies1, have an expiry date, after which the cookie will be dropped. This is done my sending either a Max-Age or Expires value when setting the cookie.

Important

There is a balance between user experience, and security around cookie lifetimes. We will see later in the module how session jacking through XSS can allow an attacker to authenticate as a given user using a captured session cookie.

  • Shorter lifetimes can mean that a user has to re-authenticate each time the cookie expires. This can cause inconvenience for users, but also reduces the security risk if a session cookie is compromised.
  • Longer lifetimes mean the user doesn't have to re-authenticate as often. However, if a session cookie is compromised this increases the length of time an exploit can take place for.2

It is also best practice to regenerate any session cookie ID's whenever a user re-authenticates (even if a cookie is already set). This can also reduce the chances of a session based compromise.

There are several other options that can be set as part of a cookie: Options can be set as part of the Set-Cookie response, using name=value pairs separated by semicolons.

  • Domain

    indicates the Domain for which the cookie can be sent. By default domain will be set to the hostname of the page sending the cookie. NOTE: Sub-domains can be included in this value. So setting domain: coventry.ac.uk will transfer the cookie for cumoodle.coventry.ac.uk, mail.coventy.ac.uk etc.

    Additionally, the domain must be part of the hostname for the site setting the Cookie. So coventry.ac.uk cannot set domain: google.com. The security reasons for this are obvious.

  • Path

    provides us with another way to control when cookies will be sent to the server. If the path option exists in the URL that is requested, then the cookie is transmitted.

    Again, this relies on the domain being set, but it gives us some fine control over which cookies are transmitted to the site. For example, if we want to include a tracking cookie for only the store part of our website (/evil.org/store/*) we can set the path to be /store.

  • SameSite

    gives us control over how a cookie is sent to "sites" or subdomains. For example, if a cookie is set for coventry.ac.uk the SameSite attribute will change if it is sent to cueh.coventry.ac.uk or github.coventry.ac.uk

    The SameSite attribute gives us some protection agaisnt exploits with 3rd party cookies (like CSRF), by restricting who can make the requset.

    • "Strict" means that only the current domain can request the cookie.
    • "Lax" means that requests for things like images will not send the cookie. However, if a user navigates to the site, (via a link) the cookie will be forwarded.
    • None means that the cookie may be forwarded to the 3rd party.

Security Specific Options

There are also a couple of Security specific options for cookies which you should be aware of:

  • secure

    is a flag that can be appended to the Set-Cookie header. When set, the cookie will only be transmitted over HTTPS.

  • HttpOnly

    Another Flag that instructs the browsers that the cookie should not be accessible via JavaScript.

Note

While we like to deride Microsoft and the security of Internet Explorer, the HttpOnly flag was their idea, and was first introduced in IE6.

However, with the exception of Microsoft!, browser support for this is still patchy, and there are a few workarounds in the wild. For an interesting discussion see: https://www.owasp.org/index.php/HttpOnly#Browsers_Supporting_HTTPOnly

Depending on the framework, these may or may not be turned on by default. Thus we can make use of packet sniffing, or XSS to nab cookies and profit (more on that when we talk about XSS).

Manipulating Cookies

Several tools exist for modifying cookies (cURL, cookie inspector/modifier in chrome) -- you should find one that works for you. This can also be done using the JavaScript Console in the web browser. We can view and modify the contents of the current pages cookies in the browser's web console.

Evidently, we cannot do this with cookies that have the HttpOnly flag set.

Examining Cookies in the Browser Console

Cookies for the current page can be read using:

document.cookie

Cookies can be set using:

document.cookie="<key>=<value>"

As well as directly editing the cookies in the console. We can also use the Network section of the developers toolbar to examine (and depending on the HTTP-ONLY sessions, modify) the cookie values.

Examining Cookies in for a request

Modern Methods of Storing data

Modern browsers also let us stash complex user data using concepts such as Local Storage. This can either let us do something similar to cookies, storing key value pairs or data, or even setup database like structures.

Local storage tends to be used through JavaScript. Unlike cookies the data in local storage will not automatically be forwarded by the browser as part of a request. Instead the script may use it either for controlling what happens when the page is rendered, or make a decision to send this information as part of a request.

An important thing to consider with local stoage is, as its intended to be used with Javascript, its vulnerable to XSS style attacks. We will look how to leak local data using XSS later in the module.

For an overview of local storage see the mozilla docs

Summary

In this article we have looked at methods for storing data on the client.

First we have taken a detailed look at cookies. These are small chunks of information, that are then forwarded as part of future requests to the server. Cookies are commonly used for things like Session Management. The concept of cookies, and sessions will become important in exploits like XSS.

We also had a brief introduction to more "modern" forms of local storage. While it may not be as common to use these for sessions for session management, they may still be used to store sensitive user information.


  1. May also be known as permanent cookies, which is not really the best name, as they need to have an expiry date set. However, its the name used in the Mozilla Docs.. 

  2. Its a really, really bad idea to set a session cookie with an expire time around 30 years in the future3 

  3. Especially if you then don't set HTTP only, or Secure, meaning you leave yourself open to XSS or Sniffing attacks. 

Back to top