Where to keep application secure data in Cookie or HTML5 Web storage
In the web application, if you are deleing with Authentication, then you do need to keep some secure data (user-specific) on the client-side. For that based on needs, we choose either LocalStorage / SessionStorage or Cookie. But let's understand when shall we opt for Cookie or storage (localStore / SessionStore).
Cookie - A cookie is a chunk of data, created by the server and sends to the client for communication purposes.
Token - Tokens, usually referring to JSON Web Tokens (JWTs), are signed credentials encoded into a long string of characters created by the server.
Why do we need to store data in the client application(browser)?
As HTTP is stateless, that means if you are already authenticated by the server but the server will not be able to track your subsequent request. It simply forgets older requests. Therefore, it's the client application's responsibility to supply the token/cookie on every request for authentication by the server. Now client application has two options to keep the data either into LocalStore/SessionStore or Cookie until a user logged out or expires the token/cookie.
Let's check the Pros & Cons of both of the methods.
What is a Cookie in detail -
A cookie is mainly created by the server and contains data that the server sends to the browser for temporary use. Session cookies are stateful elements.
The authentication data inside a cookie are stored on both the client & server. The server keeps track of the active session in a database, while the browser holds the identity of the active session. When a request is made to the server, the session id is used to look up the information such as user role, and user profile for authentication, to check if the session is still valid or not.
-
Cookies use the same session across subdomains
Example - If an application runs on yoursite.com
side and login happen in another subdomain (something like login.yourdomain.com
) then the cookie we received from login.yourside.com
can be leveraged in yourside.com
domain.
-
Cookie reduces manipulation by client-side JavaScript
- We can restrict client-side access by setting the HttpOnly flag. This reduces the likelihood of cross-site scripting (XSS) attacks on your application since most XSS attacks involve the use of malicious JS code.
-
Cookies are managed by the browser
If cookie are mentioned as HttpOnly then they will automatically send to the API call by the browser automatically.
-
Cookie requires little storage
Cookies use as little as 6 KB to store a simple user ID. Depending on what information you store in your cookie, you’ll transmit a minimal amount of bytes with every request.
There are some disadvantages of cookies as well, those are as follows -
- Cross-site request forgery attacks (XSRF or CSRF): CSRF attacks are only possible with cookie-based session handling. The SameSite attribute allows you to decide whether cookies should be sent to third-party apps using the Strict or Lax settings. A strict setting can prevent CSRF attacks, but it can also contribute to a poor browser experience for the user.
- Scaling issues: Since sessions are tied to a particular server, you can run into issues when scaling your application. In a load-balanced application, if a logged-in user is redirected to a new server, the existing session data is lost. To prevent this, sessions need to be stored in a shared database or cache. This increases the complexity of each interaction.
- Not good for API authentication: APIs provide one-time resources for authenticated end-users and don’t need to keep track of user sessions. Cookies don’t work perfectly in this case, since they track and verify active sessions.
Cookies are only secure in an HTTPS connection. Enforcing the Secure flag ensures that cookies are only sent via an encrypted HTTPS connection. Use of HTTPS prevents disclosure of session ID in person-in-the-middle (MITM) attacks.
As noted earlier, cookies can be manipulated by client-side scripts (JavaScript). This can be prevented by using the HttpOnly flag.
Structured Token - JSON Web Token (JWT)
JSON Web Token (JWT) are stateless token, meaning the server doesn’t need to keep a record of the token. Each token is self-contained, holding the information needed for verification and identification on the server.
-
Flexibility and ease of use
- JWTs are easy to use. They are self-containing nature helps us to achieve what we need for verification without database lookups. This makes JWTs more suitable to use in an API, since the API server doesn’t need to keep track of user sessions.
-
Cross-platform capabilities
- Because of their stateless nature, tokens can be seamlessly implemented on mobile platforms and internet of things (IoT) applications, especially in comparison to cookies.
-
Multiple storage options
Tokens can be stored in a number of ways in browsers or front-end applications.
If we use browser localStorage, then the application needs to manage the token to clear when not required or renew the token when expires. Subdomain can't access the localStorage data.
SessionStorage - it's the same as localStorage only drawback is token will get lost when the browser closes.
Token Security:
JWTs are cryptographically signed and base64-encoded. They’re only secure when they aren’t exposed, so they should be treated like passwords.
Token Security:
A JWT can be viewed but not manipulated on the client-side. You can take your token to jwt.io, choose the algorithm you used to sign, and see the data. You just can’t tamper with it because it’s issued on the server.
Token Security:
The lifespan of a JWT should be kept short to limit the risk caused by a leaked token. After expiration, renew the token using the refresh token.
Token Security:
Cookies give you a limit of 4096 bytes (4095, actually) — it's per cookie.
Local Storage is as big as 5MB per domain
When to use cookies or tokens
In general, the choice between a session cookie or a structured token will depend on the different use cases. We should use cookies when we need to keep track of user interactions, such as with an e-commerce application or website. Whereas we can use tokens when building API services or implementing distributed systems.
Best Practice: Angular CSRF protection when using Cookie
In the case of Angular, if you are using cookies then make sure you are leveraging the following service to make your app more secure and protect from CSRF.
If the application server sends us a token named XSRF-TOKEN, we'll use Angular's HttpClientXsrfModule to protect every outgoing request from CSRF attacks.
We'll add the HttpClientXsrfModule in the import section of the module where our component is declared: imports:[HttpClientXsrfModule]
Now, any request sent from this component automatically sends the cookie XSRF-TOKEN as the default value and header as X-XSRF-TOKEN. If we wish to use a different cookie and header name, HttpClientXsrfModule has a method called withOptions. The usage looks like this:
imports: [
HttpClientModule,
HttpClientXsrfModule.withOptions({
cookieName: 'your-custom-Xsrf-Cookie',
headerName: 'your-custom-Xsrf-Header'
})
]
In case, if you are already using any custom interceptor for your application, you can add HttpXsrfTokenExtractor as a dependency and pass the custom cookie on each request. Also, you can create a new Interceptor class by extending HTTPInterceptor and adding the same dependency (HttpXsrfTokenExtractor). Thereafter, implement the intercept() method to pass the cookie value on each request. Such as -
@Injectable()
export class CustomInterceptor implements HttpInterceptor {
constructor(private tokenExtractor: HttpXsrfTokenExtractor) {}
intercept(req: HttpRequest, next: HttpHandler): Observable<HttpEvent> {
const cookieName = 'X-XSRF-TOKEN';
let csrfToken = this.tokenExtractor.getToken() as string;
if (csrfToken !== null && !req.headers.has(cookieName)) {
req = req.clone({ headers: req.headers.set(cookieName, csrfToken) });
}
return next.handle(req);
}
}
Now in provider section on your module (i.e - app.module.ts) file you need to update the dependency as follows -
{ provide: HTTP_INTERCEPTORS, useClass: CustomInterceptor, multi: true }
{ provide: HttpXsrfTokenExtractor, useClass: HttpXsrfCookieExtractor }
Now you are done with all setup and happy to test the application and check-in network tab, is the application sending the cookie on the HTTP header or not. Let me know if you have any questions.
Thanks,
-LP
Loading comments...