In browser, we trust!
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.