In browser, we trust!

<2021-06-24 Thu>

We tend to trust in a lot of things. Implicitly and explicitly.

With evolving web technologies, you might think its getting secure. It actually is but there's a catch. HTTP is a stateless protocol. So each request is independent. In order to create a session, the server should store the info and the client should then authenticate itself in subsequent requests using the info.

How does the info get stored in client safely?

Introducing localStorage.

localStorage is a mechanism in browsers that allows you to store key-value pairs in the browser with no expiration date. The data will persist even after the browser window is closed.

The browser actually isolates localStorage of each domain. So other domains can't read the storage of another domain, so its secure in someway. But the main problem is when your app allows executing user input in the client side. Since JS can access the localStorage, the attacker might execute some JS code that reads and sends the localStorage data. It fails easily.

Introducing HTTP cookie

HTTP cookies are small blocks of data created by a web server while a user is browsing a website and placed on the user's device by the browser. Cookies are placed on the device used to access a website, and more than one cookie may be placed on a user’s device during a session.

Cookies are isolated across domains too. But still, the cookie is readable by JS so your site and users are still vulnerable.

Introducing httpOnly cookie.

httpOnly flag in the cookie doesn't allow JS to access the cookie. So the attacker can no longer steal the cookie. This is great.

If your user visits evil.com and if evil.com makes a simple fetch1, the request can be made behalf of you since the cookie is automatically sent when the request it. This is a serious problem.

Also you might need sites to make requests to your site and block the rest.

Introducing CORS

You might have heard about CORS. CORS is a way to tell your browser from your server that you are fine with accepting requests from a list of domains. Using CORS, if evil.com makes a request to your site using the cookie, your browser doesn't allow to read the response but the request will be successful. And your browser doesn't allow the client to set Origin header value.

CORS just solved half of the problem. The major problem is that, if you have an API that does modification like fetch("mywebsite/delete", { include:"credentials" }), the data will actually be deleted. CORS doesn't stop the browser from making requests.

Introducing CSRF

CSRF token2 is a unique, unpredictable value that is generated by the server and sent back to client and expects the client to pass the token in subsequent requests.

CSRF token has wide varieties. Per-session, per-request, per-form etc.,

If the server expects CSRF token in requests, evil.com can no longer make any requests to your site. Also, even if your site executes JS and got the CSRF token, the token won't be valid for other requests or APIs or forms. All it can do execute what the request is intended for.

Summary

Use httpOnly flag in (auth) cookie and enable CORS with your allowed third-party domains and use double-submit CSRF token3 to secure your site.

In browser, we trust.

Browser isolates localStorage by domain, cookies, doesn't allow JS to read httpOnly cookies, doesn't allow the client to set the Origin header, doesn't allow to read a response if it doesn't have CORS header etc.,

It is what makes things secure.

So for a browser to be privacy first, it first has to be more modern and bug free.

You can also find the tweet here.

Footnotes: