Browser Cookies 101

A Detailed Introduction: incl. Implementation, Security, Alternatives, and Recent Developments

Gabbie Piraino
The Startup
12 min readApr 3, 2020

--

When building web applications, it is likely that you’ll eventually come across cookies — and no, not the chocolate chip variety. A browser-implemented technology, cookies can be leveraged to implement modern internet functionality.

At its most basic level, an HTTP cookie (also known as a web, or browser cookie) is a small piece of data that typically originates from an HTTP server. Cookies cannot exceed 4KB of textual key=value data, and are stored locally by a client’s browser on their disk. Cookies are private to the domain that sets them; in plain English — the browser only allows websites to read, write, and delete their own cookies. Most browsers limit the number of cookies any single domain can set to approx. 20–25 cookies (the total number depends on the browser itself) in order to prevent local disk space consumption. Also, because cookies are browser-specific, a server cannot utilize cookies set in one browser for the same client in another browser. That said, different tabs or windows from the same browser can all access that client’s cookies.

Cookies were first introduced to the web in 1994, and have been further defined as recently as 2011, in the RFC 6265 standards. When you consider that HTTP is a stateless protocol, the creation of cookies allowed web developers to implement state in an otherwise stateless HTTP request. The most common uses for cookies include managing a client’s session, or authentication of users; tracking clients; and personalization. By using cookies, a domain can recognize the same client and keep them logged into an application, serve them relevant, personalized information (think social media newsfeeds), or even keep track of their navigation (third-party advertisement).

On a functional level, a client makes an initial HTTP request, which is ultimately received by the server. The server responds with an HTTP response with a directive to set a cookie. The browser receives both the response and the cookie, and persists the cookie locally on the client’s disk. When future HTTP requests are sent from the same client, the cookie is included, and the server can utilize the associated data in the cookie to recognize the same client and create stateful responses. As a note, the server is unable to confirm if the cookie was set on a secure origin, or even tell where the cookie was originally set, it can only read the cookies associated with the respective domain.

As an aside, cookies can be set and read both on the server-side, as described above, and also on the client-side, as exposed in the browser’s Document object. Below, we’ll dive more deeply into implementing both server-side and client-side cookies.

Implementing Cookies

When implementing cookies, it’s important to know that there are two types of cookies: session and permanent cookies. A cookie, by default, will persist as long as the browser window is open. Upon closure, a cookie is typically deleted along with the client’s current session; hence, these are session cookies. A permanent cookie, therefore, would last longer than the current session. This can be accomplished by setting an expiry date within the cookie itself. With browsers now implementing session restoring, a session cookie will not be deleted immediately upon a browser window being closed and will act like a permanent cookie.

Creating Cookies Server-Side

When creating a cookie, a server can send a Set-Cookie header along with the HTTP response back to the client. This header will alert the browser to create and store the cookie. When further HTTP requests are made, the browser will automatically include the Cookie header.

The most basic cookie is set with the following syntax:

Set-Cookie: key=value;

Implementing a Cookie header with different servers will look slightly different due to the nuances of syntax across different languages.

With NodeJS, a cookie could be set as simply as response.setHeader('Set-Cookie', 'key=value'); with a string value, or with an array of strings to include multiple values associated with the same cookie: response.setHeader('Set-Cookie', ['id=1', 'name=Jane']); To delete a cookie, you can set the Expires flags (more details below) to a date in the past, the Max-Age flag to 0, or with ExpressJS by utilizing the clearCookie() method with all of the same cookie flags.

In Ruby on Rails, a cookie can be read and set directly through the ActionController Cookies method. Reading a cookie only returns the value that it holds, not the actual cookie object. A basic cookie could be set with cookies[:name] = “Jane” or will multiple values as

To read in Rails, you simply need to call cookies[:name] and it will return the value. To delete a cookie, the delete method can be utilized: cookies.delete :name but be aware, if the domain was specified when setting the cookie, it must also be specified when deleting a cookie in Rails.

Cookie Flags

In addition to the data that you want to pass into the cookie, additional flags can be set for further specificity.

Expires and Max-Age

In order to create a permanent cookie, an expiry date needs to be set. This can be accomplished with either a specific date and the Expires flag, or a specific length of time with the Max-Age tag.

Set-Cookie: id=1; Expires=Friday, 3 Apr 2020 00:00:00 GMT;

Set-Cookie: id=1; Max-Age=31536000; (this cookie would expire in one year)

Domain and Path

The Domain and Path flags determine the scope of a cookie, or what sites a cookie may be sent to. When set, Domain specifies allowed hosts, including subdomains. Without this flag, the default behavior is to only allow the host of the current site, excluding relevant subdomains. The Path flag specifies a URL path that must be included in the requested URL in order to allow the cookie to be sent with the HTTP request. When setting the flag, by using the forward slash, subdirectories will also be included, i.e. Path=/test will also allow Path=/test/1 and Path=/test/1/custom-path

Set-Cookie: id=1; Path=/custom-path;

Set-Cookie: id=1; Domain: medium.com;

Secure and HttpOnly

In an encrypted request sent over HTTPS protocol to a server, cookies can include the Secure flag, though it doesn’t offer real protection. Cookies themselves are inherently insecure and sensitive information should never be stored in a cookie. Some browsers (Chrome and Firefox 52) have started preventing insecure site from setting cookies with the Secure flag.

Further, cookies can also be set with the HttpOnly flag. This prevents the cookies from being accessible in the Document object to Javascript; they will only be sent to the server. For cookies that only need to persist server-side session information, this flag should be utilized.

Set-Cookie: id=1; Secure; HttpOnly;

SameSite

In order to prevent a cookie from being send cross-site requests, understanding that the site here is the registrable domain, the SameSite flag can be set. It can have one of the following attributes: None, Lax, or Strict(case-insensitive). None allows cookies to be sent either same-site or cross-site. Lax will allow cookies to be sent when a client navigates to the domain from an external site, such as via link. Otherwise, the cookies are withheld on cross-site subrequests. Lax is commonly the browser default. Strict only allows the browser to send cookies for same-site requests.

Set-Cookie: id=1; SameSite=Strict;

Setting Cookies Client-Side

Cookies can also be created on the client-side by accessing the Document.cookie object with Javascript. However, as noted above, if the HttpOnly flag was set when the cookie was created, then these cookies are not accessible from the client-side.

In order to create a cookie, similar to the NodeJS example above, you simply pass in the value and any applicable flags as a string: document.cookie = “name=Jane”; and you can read directly from the object: console.log(document.cookie); which would return “name=Jane”. In order to delete a cookie, simply overwrite the value as empty, and set an expiry data in the past: document.cookie = “name=; expires=Thu, 01 Jan 1970 00:00:00 UTC;”;

Security with Cookies

When implementing cookies, it’s important to be aware of and consider the security risks. There are two main methods to breach security: XSS and CSRF attacks. We’ll explore both.

Cross-Site Scripting (XSS)

One of the most common usages of cookies is to store client data and an authenticated user session. If a hacker were to steal the cookie with this information, that client’s data or current user session could be exploited. XSS, or Cross-Site Scripting, allows hackers to inject malicious client-side code in order to bypass controls and impersonate users. The browser itself cannot determine if the script is untrustworthy, so the hacker can access that client’s cookies, as well as tokens and site-specific information.

In order to mitigate these attacks, setting cookies with the HttpOnly flag prevents hackers from accessing a client’s cookies through Javascript. Additional security to prevent XSS can also be implemented with Content Security Policies.

Cross-Site Request Forgery (CSRF)

A Cross-Site Request Forgery is an attack that utilizes an authenticated user’s session and sends a site unwanted commands. It’s possible to create a CSRF by including malicious parameters in a URL that should go somewhere else. For example, if a client is logged into their bank account with valid cookies, it is possible that another tab or browser window (really, another site) has loaded an “image” with a URL request to withdraw money from your account and transfer it elsewhere. When the HTML on that other site loads, it will trigger the transfer immediately without preventative measures.

To prevent these attacks, there are several avenues to consider when focused on cookies. The first is to set the SameSite flag to either Strict or Lax for sensitive user actions to prevent untrustworthy cross-site requests. CSRF tokens (generated upon user sign-on) could also be implemented in hidden input fields for forms. The server can compare the received token against the expected token as another form of validation. By deploying both SameSite cookies and CSRF tokens, browsers can better protect against CSRF attacks — even those originating from a different subdomain.

Tracking & Privacy with Third-Party Cookies

Like session and permanent cookies, cookies can also fall into one of two categories: first-party or third-party cookies. All cookies are set with a specific domain (the developer can also specify this with the Domain flag). When the client’s current domain matches the domain of a cookie, that cookie is considered a first-party cookie. When the domain is different, it is a third-party cookie.

When cookies are set through a third-party component — either an image hosted on another domain’s server, or a component similarly hosted on another domain’s server (i.e. an ad banner) — they create third-party cookies. These cookies are primarily used for tracking and advertising purposes. Some browsers (more information below) allow clients to block third-party cookies, though the default behavior in browsers for many years was to allow third-party cookies by default.

An additional DNT (Do Not Track) header can be included in HTTP requests to allow the client to indicate their preference for privacy instead of more personalized content.

Cookie Alternatives

With the advancement of HTML5, Web Storage allowed developers to implement state in a more secure, less structured manner. Every browser supports Web Storage.

The storage limits far exceed cookies (at least 5MB as compared to 80KB collectively), and any page associated with the same origin — both domain and protocol — can access Web Storage. As a short aside, CORS (Cross-Origin Sharing Standard) can further enable cross-site HTTP requests, especially in conjunction with the Fetch API. Similarly to session and permanent cookies, Web Storage provides two objects to store data: sessionStorage and localStorage, respectively. The localStorage object persists data beyond when the browser is closed, without expiration, whereas sessionStorage stores the data until the client closes the specific browser tab.

In order to set, read or delete data set in the Web Storage, you can implement as follows:

With the popularization of Single Page Applications (SPAs), setting and maintaining cookies in order to implement state across multiple HTTP requests is somewhat moot; a SPA can dynamically render new content without refreshing the page.

Furthermore, the rise of JWTs (JSON Web Token) have mitigated the need for a standardized, secure container format — optionally validated and/or encrypted — to transfer information between two parties. JWTs can be utilized to communicate information between the server and browser, commonly for authentication and authorization of users. To be clear, JWTs can be implemented with both cookies and local/sessionStorage; with a SPA, the JWT can easily be set in Web Storage (either local or session as most appropriate) after an initial API call to procure the token and then added to every subsequent request to the server.

The potential drawbacks of utilizing Web Storage is that it can also be targeted by XSS attacks, and information stored (such as a JWT) needs to be manually sent with each new HTTP request. Moreover, sessionStorage doesn’t allow for multiple tab or browser access, and localStorage is never automatically purged — it must be cleared manually. On the other hand, session cookies are deleted upon a client closing the browser, and permanent cookies can be managed with expiry dates.

Recent Legislation

In 2009, the European Union passed Directive 2009/136/EC, also known as the e-Privacy Directive. Specifically, it required all websites that are owned by EU companies or international sites that cater to EU citizens to inform clients of cookie usage and gain their consent before persisting cookies in the browser. Clients also need to be given the option to disallow cookies. The utilization of cookies with the express purpose of basic functionality, i.e. a checkout cart, were excluded. To be clear, utilization of Web Storage was also considered to be included in the directive. The intent was to better educate consumers regarding what personal information is being collected and how it’s being used. As of May 2012, each member state in the EU had enacted legislation to fulfill the directive.

In May 2018, a more stringent and expansive law, the General Data Protection Regulation (GDPR) established that companies were required to follow ten principles in order to collect and use consenting clients’ data. The principles include: lawfulness, fairness, transparency, purpose limitation, data minimization, accuracy, storage limits, integrity, confidentiality, and accountability.

In practice, GDPR’s territorial scope expanded upon that of the e-Privacy Directive: any companies that offer goods or services, or monitor the behavior of individuals located in the EU must comply. When sanctioned, enforcement agencies have fined corporations thousands to several hundred million Euros for non-compliant activity. With this in mind, it’s important to consider how the utilization of client data in cookies needs to be compliant with new and upcoming legislature.

Cookies Across Browsers

Since 2017, Safari — Apple’s browser — began implementing its Intelligent Tracking Prevention to enhance client privacy. It initially restricted cross-site tracking third-party cookies, but later further expanded to require 7-day expiry for first-party cookies in Safari 12.1 in OS High Sierra and Mojave.

Mozilla’s Firefox has since followed suit, implementing Tracking Protection in Private Browsing and then expanding with Enhanced Tracking Protection in 2019 to block cookies from known third-party trackers. Now the default setting, it increases the difficulty for companies to track clients’ movements around the web.

One of the last major browsers to explore cookie limitations is Chrome. In early 2020, Google announced a phased approach to block third-party cookies over the next two years. Because some sites’ functionality and much of the existing third-party advertising is dependent upon third-party cookies, Chrome’s intention is to create new technical solutions to replace cookies so that site infrastructure won’t break while also balancing advertiser needs, potentially with anonymous tracking and targeting of demographics instead of unique individuals to ensure better client privacy.

That said, while each of the browsers have their own opinions on the best solution, there is, as of yet, no set solution. Potential options that some browsers have agreed to pursue include implementing privacy sandboxes instead of fingerprinting — a browser would allow data collection only up until a specific cutoff point — or potentially creating an API to track client conversions for e-commerce. Because cookies can be implemented in a wide variety of ways, a single solution to replace their usage is unlikely and it will take time to find solution commonality amongst the browsers.

Conclusion

As you can see, as the Internet continues to develop and standards change, new methodologies emerge to manage client state. Whether you prefer cookies or Web Storage, it is important to understand the pros and cons of each option. More information is available from the sources throughout and below for further learning beyond this introduction to cookies. Hopefully now you can more effectively determine what fits your own needs, and how you might implement cookies within your own web applications.

Good luck, and happy coding!

Sources

Internet Engineering Task Force: Standards Track 6265

MDN Web Docs: HTTP cookies, Document.cookie, XSS, CSRF, DNT, CORS

Flavio Copes: Learn how HTTP Cookies work

OWASP: Cross-Site Request Forgery Prevention Cheat Sheet

Privacy Policies: The Must-know Guide to the EU Cookie Directive

Law Office of Richard A Chapo: General Data Protection Regulation (GDPR)

The Mozilla Blog: Enhanced Tracking Protection by Default

Chromium Blog: Building a more private web

The Verge: Google to ‘phase out’ third-party cookies in Chrome, but not for two years

--

--

Gabbie Piraino
The Startup

Current Tech Geek | Previous Book Nerd | Always Doggo Lifestyle