Know The Web: HTTP Cookie 🍪
Souvik Kar Mahapatra
Posted on February 17, 2021
In this post, we are going to learn about Cookie certainly not the edible one. We'll discuss cookie properties and security stuff related to HTTP cookies, also create cookie on the way so make sure that you and your patience grab milk and cookie, enjoy the post.
Cookie Time!
While using Facebook, Instagram, or any other services online did you notice that once you logged into these services you don't have to log in when you visit these sites again?
You searched for shoes and the next moment when you visit any site, you get to see ads related to shoes.
Is there some mind-reading stuff going on?
To define, cookies are small chunks of temporary data (key-value pair) in the browser which helps in various functionalities in any web services (as mentioned above). These web services/websites setup cookie into your browser and use for features like managing you session on their service/website, to track you and stuff like that. They can also be used to remember pieces of information that the user previously entered into form fields, such as names, addresses, passwords(not a good idea😅), and payment card numbers.
Now as these websites/web services are able to access the cookie they place in your browser which makes it clear that, "every time you make a request to the website/web service, the cookie is sent to the server along with the request".
🕵️♂️ Sherlock mode ON!
Let's head over to a random site and have a look at their cookies. On the way, I'll explain about the properties. So I am heading to motherfuckingwebsite.com. In developer tools open the Application tab and then to cookie > https://mothe....
There you get to see the following:
Those with green underline are options. Name & Value are self explanatory. The rest are what we need to understand.
- Domain
Each cookie has a domain pattern to which it belongs and can only be accessed by that specific domain pattern.
If a cookie named cookie-1
is added for .motherfuckingwebsite.com
(notice the .
) then cookie-1
can be accessed by any subdomain of motherfuckingwebsite.com. Example: cookie-1
can be accessed by the domain motherfuckingwebsite.com
as well as its subdomain like www.motherfuckingwebsite.com
or www2.motherfuckingwebsite.com
and so on.
If a cookie named cookie-2
is added for a subdomain xyz.motherfuckingwebsite.com
then it can be only accessed by its subdomain and itself. Example: cookie-2
can be accessed by subdomain xyz.motherfuckingwebsite.com
and its subdomain abc.xyz.motherfuckingwebsite.com
and so on.
you can read more at RFC2109
- Path
Suppose you want to make a cookie accessible to a specific path then this option is used. Will explain in a while.
- Expires/Max-age
As I have mentioned right in the start that "cookies are temporary data" i.e they have a validity duration after which they expire. How is validity duration determined? By the web service/website. Whenever a website/web service creates a cookie, it also mentions its lifetime.
HttpOnly, Secure and SameSite will be explained in the security section.
Okay! enough talks. Let's create some cookies, heat up your oven (browser)
👨💻 The Client Way
First we'll discuss about creating cookie from the client-side i.e from the browser using JS which is pretty easy.
document.cookie
How about having a look at existing cookie using JS? Just use document.cookie
in the console and you'll see the following:
Notice, each cookie is separated by a semicolon(;
).
- creating simple cookie
document.cookie="itsME=1"
NOTE: Above code doesn't override cookies. It only created a new one.
You can see it's defined for domain motherfuckingwebsite.com
now as per the properties we have discussed above, www.motherfuckingwebsite.com
should not be able to access the cookie itsME
.
and we don't see the cookie that we created hence we verified the properties.
- setting up cookie path
How about adding the Path option to our cookie? Let's go...
document.cookie="itsMe=7; path=/test";
The above code will only set cookie for motherfuckingwebsite.com/test
and can only be accessed by it. Here is the example.
document.cookie="itsME=7; path=/test";
Image 1: we are accessing cookie from motherfuckingwebsite.com
and there is no such cookie.
Image 2: we are accessing cookie from motherfuckingwebsite.com/test
and we can see it.
- Setting cookie lifetime
Let's create a cookie with an expiry date. Now we can do this in two ways.
- Expires: Takes date as value.
//86400e3 is same as 86400000 i.e 24 hours in milliseconds
var exp_date=new Date(Date.now()+86400e3);
//refer template literals in JS if not familiar with ${}
document.cookie=`itsME2=2;expires=${exp_date.toGMTString()}`;
- Max-age: Takes time (in seconds) as value.
//86400 i.e 24 hours in seconds
document.cookie=`itsME3=3;max-age=86400`;
Above we have created both the cookie with a validity of 24 hrs. from the time the cookie was created. Here you can compare all three cookies we have set so far.
Notice! in the Expires/Max-age part you can see ItsME2
and ItsME3
has some date and time but ItsME
shows session. It is so because when you don't mention any expiry time of the cookie then the browser considers it as a sessional cookie and it expires as soon as you close the browser. Go ahead, give it a try.
💡 Head over to didthanoskill.me and look for cookie from the URL bar. You'll see 1 cookie in use. When you do
document.cookie
in the browser console, an empty string is returned which is weird. Go to the Application tab in the developer tool and there also you'll see no cookie. Any idea why is so? Hint: have a look at the source and if still don't understand then run the debugger in the dev tool to understand why is it happening so?
🖥️ The Server Way
We saw the client's Way of creating cookies. Now we'll create a cookie from the server-side and I'll use NodeJS and express for this.
Basically what happens is when the client makes a request to the server, the server responds with a response which contains header and in that header, there is set-cookie
option which tells the browser to create a cookie.
- creating a simple cookie.
const app=require("express")();
app.get("/",(req,res)=>{
//setting response header
res.setHeader("set-cookie",["itsSERVER1=h1"]);
res.send("this is https://localhost:2000/");
});
app.listen(2000,()=>{
console.log(">2000<");
})
and we have it.
- setting up cookie path
const app=require("express")();
app.get("/",(req,res)=>{
/*can also use res.setHeader() instead of
res.cookie()*/
res.cookie("itsSERVER1","h1");
//for path /hahahayes
res.cookie("itsSERVER2","yeet!",{path:"/hahahayes"});
res.send("this is https://localhost:2000/");
});
app.get("/hahahayes",(req,res)=>{
res.send("this is https://localhost:2000/hahahayes");
});
app.listen(2000,()=>{
console.log(">2000<");
});
gives following result:
so on and so forth for other options as well.
🔒 Security
Security is a very important topic of discussion over here. As mentioned earlier, services like social media use various cookies to keep you logged in. If such cookies get in hands of attackers they can easily break into your account and the rest you know.
When user privacy is a concern, it's important that any web app implementation invalidate cookie data after a certain timeout instead of relying on the browser to do it.
If you are using cookie to store some data and later rendering it in DOM (which is a super duper bad practice) then make sure to keep the valid formatting, they should be escaped using a built-in encodeURIComponent function:
var cookie_name="mycookie";
var cookie_value="myvalue";
document.cookie = `${encodeURIComponent(cookie_name)}=${encodeURIComponent(cookie_value)}`;
In section The Client Way, we easily accessed the website's cookie using JavaScript, so an attacker may find a vulnerability like XSS which enables them to execute malicious JS code on the website and bypass logins. From a developer's point of view, it's really hard to keep track of XSS especially in humongous applications with a lot of features. Due to this, some inbuilt security features are there in cookies, which prevent such attacks even if the attacker is able to execute some code.
You can check out Hack this site basic 10 which demonstrates, what careless use of cookies can lead to.
HttpOnly is an option used by web-server when they set cookies. This option forbids any JavaScript access to the cookie. This is a precautionary measure, to protect from certain attacks.
//server side
const app=require("express")();
app.get("/",(req,res)=>{
/*can also use res.setHeader() instead of
res.cookie()*/
res.cookie("itsSERVERsecure","100",{httpOnly:true});
res.send("this is https://localhost:2000/");
});
app.listen(2000,()=>{
console.log(">2000<");
});
and you'll see a tick mark (✔️) under HttpOnly in the Application tab (developer tools). Try accessing it using JS.
If your cookie contain sensitive content then you may wanna send it over HTTPS. To accomplish this you have to include secure option as shown below.
//client side
document.cookie = "ItsMeSecure=6; secure";
//server side
const app=require("express")();
app.get("/",(req,res)=>{
/*can also use res.setHeader() instead of
res.cookie()*/
res.cookie("itsSERVERsecure","100",{secure:true});
res.send("this is https://localhost:2000/");
});
app.listen(2000,()=>{
console.log(">2000<");
});
samesite SameSite prevents the browser from sending the cookie along with cross-site requests. Possible values are lax, strict or none.
The lax value will send the cookie for all same-site requests and top-level navigation GET requests. This is sufficient for user tracking, but it will prevent many CSRF attacks. This is the default value in modern browsers.
The strict value will prevent the cookie from being sent by the browser to the target site in all cross-site browsing contexts, even when following a regular link.
The none value explicitly states no restrictions will be applied. The cookie will be sent in all requests—both cross-site and same-site.
So make sure that you use cookies wisely 🦉.
Feel free to point out any issues or suggest improvements in the content.
🥳 So it's time to wrap up the post with a quote
"Opportunities don't happen. You create them" -Chris Grosser
Posted on February 17, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.