See previous part: Why Do We Need Refresh Token? Do You Know How to Securely Store Refresh Token and Access Token in the Browser?.
In the previous article, we learned about why we should use Refresh Token. The issue at hand is that if the Access Token is stolen, there is a high chance that the Refresh Token will also be compromised. So what's the point of generating a Refresh Token when the possibility of losing both is the same?
To find the answer to this issue, many debates have emerged and it seems that there is no definitive conclusion because everyone has valid points. I play the role of an audience sitting in the stands of a football field, absorbing their opinions and synthesizing them to provide the most satisfactory answer. Of course, it is not entirely accurate and I hope readers can find any inconsistencies in it.
My final answer is "in the browser." Depending on the level of security you aim for, you can choose the most suitable option to save time and cost. Inside the browser, there are several storage methods such as Cookies, localStorage, sessionStorage, and even a server-side storage called Session. Each method has its own business logic, and cleverly organizing the storage of Access Token and Refresh Token in it helps minimize the severity of XSS attacks.
A fact is that if your website is attacked by XSS, regardless of where you store them, the chances of Access Token and Refresh Token being leaked are high. To make it easier to understand, let's dissect the nature of an XSS attack. An XSS attack occurs when the attacker can run JavaScript code on your website. This means that the attacker can retrieve the access token stored anywhere the JavaScript code has access to. An XSS attack can occur through third-party JavaScript code in your website, such as React, Vue, jQuery, Google Analytics, etc. The more popular the library, the greater the attention it attracts, and once it is compromised, the damage can be enormous.
It is clear that not using any third-party library in your website is very difficult. Every library added increases the risk. Attackers can also exploit XSS through form/input fields on your website. For example, a public chat feature can be vulnerable to a JavaScript code that steals data. If the display of chat content is not properly handled, other users accessing the website can easily get infected. A MIME sniffing attack can also result in an XSS attack.
Parallel to XSS is a CSRF (Cross-Site Request Forgery) attack targeting the Access Token. It is understood as an attack that forces the user to perform unintended requests. The attacker does not directly steal the Access Token or Refresh Token but takes advantage of the Access Token attached to each request to the server.
For example, a website allows users to change their email through an API:
POST /email/change HTTP/1.1
Host: yoursite.com
Content-Type: application/x-www-form-urlencoded
Cookie: sessionID=qwerty
[email protected]
The attacker creates an automatic form that sends a POST
request to /email/change
with their email attached. At that time, the session will be automatically added to the request because you are directly accessing the website, but you are unaware of the presence of that hidden form. However, this can be minimized by using `sameSite`.
From there, it can be concluded that in order to prevent the leakage of Access Token and Refresh Token, they must be stored in a location where JavaScript code has no access. Is there such a place in the browser? Yes, there is, and it is the `httpOnly` cookie. But is httpOnly
the ultimate solution? Before answering, I want you to have a clearer understanding of common storage mechanisms in browsers and servers.
Session is one of the most commonly used ways to identify user sessions in server-side render web applications. The working mechanism is quite easy to understand. The server generates a session ID for each request to identify the session, the browser saves that ID and sends it along with all subsequent requests.
This method requires the server to store and manage sessions for each client. The session ID is typically stored by the client in a Cookie or as a parameter in the URL. This still makes it susceptible to being stolen through an XSS attack.
No need to say much, a Cookie is information stored on your computer by a website you visit. It is used to store information you need on a website, such as user login information... Cookies have been one of the oldest methods used for this purpose. The information stored in a Cookie is sent to the server through request headers, allowing the server to identify the user's session.
JavaScript has access to Cookies, so they can still be stolen by an XSS attack.
However, there is a concept called httpOnly
for Cookies. If a cookie has the additional httpOnly
option specified, it is immune to JavaScript. This means that JavaScript does not have access to the httpOnly
cookie, and it is automatically sent with each request to the server.
These are two storage methods with much larger capacity than Cookies. Therefore, they are often used to store large amounts of information or as cache memory for website features to ensure smooth performance.
Information in localStorage is persistently stored until you delete it. On the other hand, sessionStorage is usually cleared after you end your session with the website (close tab, close browser...).
JavaScript has access to both, so they can still be stolen by an XSS attack.
From there, it can be concluded that there are different ways to store:
httpOnly
cookie -> vulnerable to CSRF, but can be mitigated. Better than the first option. httpOnly
cookie -> safe from CSRF. Although the Access Token could be stolen, it only exists for a short time, so the risk can be minimized.It can be seen that the third method is more advantageous than the first two methods. Setting it up is not too complicated. Just when logging in or authorizing, the Access Token is returned in the response body, while the Refresh Token is only returned through the httpOnly
cookie.
That's the storage method to minimize the leakage of Access Token and Refresh Token. In case Access Token and Refresh Token are leaked, is there any way to detect or prevent it? I will continue with another article in this series. Thank you for following along.
5 profound lessons
Every product comes with stories. The success of others is an inspiration for many to follow. 5 lessons learned have changed me forever. How about you? Click now!
Subscribe to receive new article notifications
Hello, my name is Hoai - a developer who tells stories through writing ✍️ and creating products 🚀. With many years of programming experience, I have contributed to various products that bring value to users at my workplace as well as to myself. My hobbies include reading, writing, and researching... I created this blog with the mission of delivering quality articles to the readers of 2coffee.dev.Follow me through these channels LinkedIn, Facebook, Instagram, Telegram.
Comments (4)