Let’s taste some Cookies

Suriya
Javarevisited
Published in
7 min readDec 17, 2022

Strictly for devs — localhost-ing

Most of us know what a Web Cookie is. But just in case, if you do not know, a simple google search can bring it to the light.

Image generated by openai

This post covers mostly the questions that a dev might have while actually implementing a cookie, rather than reading them in theory.

Contents

This post is about exploring all the fields with a simple JavaScript example.

Cookie table

The cookie table has multiple fields. Here is a Sample JavaScript application running in local,

F12 — Opens all in one developer toolbox. Navigate to Application tab -> Cookies

Who can set the cookie ?

  • The Cookie can be set in the JavaScript client code using,
document.cookie = 'username=hello world'
  • A cookie can be also set from the server response in the Set-Cookie header,
A httpOnly Cookie sent from the server

Default fields

As we can, there are four fields that are defaulted say,

  • Domain
    This specifies that only the host localhost can read the Cookie. If trying to access from any other domain 127.0.0.1 it will not show up the cookie as string localhost != 127.0.0.1
127.0.0.1 not showing up the Cookie that we set earlier
  • Path
    Cookies are only visible in the path set. It defaults to the current path in the url.
As we can see the same cookie is not showing up for the url path - /server
  • Expiry/Max-age
    By default set to Session(mostly when the browser is closed but varies based on the broswer and user settings). When an explicit expiry or a max-age is set the cookie is removed from the cookie table.
  • Priority
    Priority is set to medium.

Can a Cookie be accessed in a subdomain or vice versa ?

Nope by default. However it can be achieved when the Domain is set explicitly as in the following,

document.cookie = 'username=suriya;domain=localhost.com'
Example showing cookie cascading to subdomain

Well, this works ok when the the Cookie is set in the client, but how about when the Cookie is set from the server and send back to the client in the response ?. Let’s check it out in Set-Cookie within sub-domain and cross-domain sections.

How to delete a Cookie ?

Setting the expired expiry date to the Cookie key makes the lifetime out of bound, removing the Cookie from the cookie table.

document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";

Where can a Cookie be used ?

It remembers stateful information for the stateless HTTP protocol. Cookies are mainly for three purpose,

  • Session management
  • Personalization
  • Tracking

Can multiple tabs running same domain update the same Cookie key ?

Different tab/window in the same browser— Yes. The Cookie is based on domain field. If different tabs are running the same domain then each tab can update the cookie value by its key.

How to make a cookie unreadable in JavaScript ?

Cookies, that are created via client code is always readable by the client code.

However, the Cookie that’s created by a server response header Set-Cookie with HttpOnly field makes a Cookie unreadable to JavaScript like a magic.

Sub-domain Set-Cookie

Let’s to demonstrate this case,

  • run the server at server.localhost.com
  • run the client at client.localhost.com

here, the server and client are subdomains of localhost.com represented as .localhost.com in the Cookie table

Code changes

To have it working, we need to update our Client code http.withCredentials = true,

    const http = new XMLHttpRequest();
const url='https://server.localhost.com:3000/server';
http.open("GET", url);
http.withCredentials = true;
http.send();

Also, we need to set our Server code with,

  • Accept the request from the origins
  • Allow access to the credentials
res.setHeader('Access-Control-Allow-Origin', 'https://client.localhost.com:5500');
res.setHeader('Access-Control-Allow-Credentials', 'true');

This requires the connection to be secure meaning, the server application need to be on https.

res.setHeader('Set-Cookie', 'where=server;domain=localhost.com;Secure;expires='+ getUtcTimeInSecondsFromNow(60));

Check this post to generate a Self-singed certificate,

Note The client application does not need to be on https. However, for this demonstration purpose to mimic the production environment, running the client on https as well.

With no HttpOnly field

A typical http call for Set-Cookie without HttpOnly

The following screenshot shows, the sub-sequent http call to the same domain does not have the cookie value set when the HttpOnly is missing.

Set-cookie without HttpOnly cookie is not sent back to the server on subsequent call

With HttpOnly field

The following is with the HttpOnly field set in the response,

HttpOnly cookie

The above makes it unreadable for the JavaScript code even though it shows up in the Cookie table.

When the Read Stored value button is clicked to read it, it displays nothing,

HttpOnly cookie unreadable in JavaScript

Also only the cookie that’s HttpOnly is only sent back to the server,

Screen shot showing only the HttpOnly Cookie is sent back to the server on the very next call

Cross-domain Set-Cookie

The cross domain cookies that are set by the server response do not show up in the Cookie table.

But, they are sent to the same domain in the subsequent request for furthur server validation, provided the response has following fields,

and the following field removed,

And trying it in a non incognito window or else it might ask to change the user preference.

For demonstration purpose we can,

  • run the client at clienthost.net
  • run the server at server.localhost.com

Why do they say that Cookie is unsecure ?

Cookies are prone to XSS and CSRF attacks.

How can we secure the Cookie ?

To tackle from the attacks and to avoid information loss, we need to be aware of the following,

Issues and remedies

CORS domain access

Error Access to XMLHttpRequest at ‘https://server.localhost.com:3000/server' from origin ‘https://clienthost.net:5500' has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

Add the following response header in the ,

 res.setHeader('Access-Control-Allow-Origin', 'https://clienthost.net:5500');

Incorrect domain set in the Set-Cookie response

Warning This attempt to set a cookie via a Set-Cookie header was blocked because its Domain attribute was invalid with regards to the current host url.

Check the following,

Blocked due to user preference

Warning This attempt to set a cookie via a Set-Cookie header was blocked due to user preference.

Try using a non-incognito window or change the settings of the user preferences.

Final take

Cookies are a useful tool for storing information about a user’s browsing activity and preferences. They can be used to personalize a user’s experience on a website and to track a user’s browsing activity across multiple websites.

However, it is important to use cookies responsibly and to respect user’s privacy. This means being transparent about how cookies are used and giving users the ability to control how their data is collected and used. It is also important to consider the security implications of storing sensitive information in cookies.

In general, it is a good idea to use cookies only when they are necessary and to minimize the amount of personal data that is stored in them. It is also a good idea to give users the option to opt out of cookie tracking, and to delete or block cookies when they are no longer needed.

The fields that we missed to cover are,

Which we will cover in another localhost-ing post !

--

--

Suriya
Javarevisited

I am a full-time Software Engineer and a passionate Landscape Photographer. For more info visit https://suriyaprakhash.com