Why is BFF pattern deemed safer for SPA's? - cookies

I am designing a new web application which requires an oAuth2 implementation. I've been reading up on oAuth2 Authorization Code flow with PKCE. That makes sense, it ensures that de client who is initiating the Authorization Code flow is the same client as the one who is exchanging the authorization code for access token (and/or refresh token).
But then I was wondering on how we could deal with refresh tokens. I understand that BFF is now the preferred solution for this, where we use a separate component (Backend for Frontend) that handles all calls from the web app and proxies those to the backend api, all the while handling all access tokens and refresh tokens. The web app and BFF maintain a session cookie, so the BFF can track which access token should be added to which request and so forth.
Most blogs mention something in the lines of "and this is safe if you set the session cookie to strict and http only and secure, because no malicious JS can get that cookie then".
And that is where I have trouble understanding why this is safer. If cookies are safe enough to deal with session id's, then why are they not safe enough to deal with access tokens? Or even refresh tokens? If they are cookie based, then they are sent with each request and no malicious JS can access it. If they could, then the BFF model doesn't provide any additional security, just a little more complexity, no?
So bottomline is: if BFF is deemed safe(r) because the sessions are kept in secure http-only cookies, why is keeping access/refresh tokens in secure http-only cookies not safe?

Adding a BFF to the mix does change the security of using tokens. The BFF is a confidential client so it makes the whole solution more secure, for sure, but this is not the only reason you would use a BFF. One of the main benefits is to keep tokens away from the browser. You don't want the tokens to be accessible by Javascript, that's why you want to rely on cookie-based sessions instead. This protects you from XSS attacks that want to steal the tokens. However, using sessions opens you to CSRF attacks and session-riding attacks. Protecting against CSRF and session-riding should be a bit easier than mitigating XSS as you can become vulnerable to XSS through a third-party library's dependency, for example.
E.g. in case of BFF: steal session from cookie -> make request to BFF -> get access to user data. In case of no BFF: steal AT/RT from cookie -> make request to API -> get access to user data. I still don't understand how this is safer, I am sorry for not understanding it.
You don't have to be sorry! It's good that you're trying to understand that.
The problem with your example is this: you assume that there is no BFF, but AT/RT are kept in cookies. If you're using cookies then it means that you have some sort of a backend component that sits between your SPA and APIs. Otherwise, you would have to deal with tokens in the browser (readable by JS). So the difference that you should be contemplating here is — am I using HTTP-only cookies to call my APIs or do I need tokens and set Authorization headers in JS? For the former case, it doesn't matter if you have a session ID in the cookie or the actual AT. The important part is that JS can't read the content of that cookie.
Another thing is that it's harder to steal sessions than tokens kept in JS. For someone to steal data from cookies you would need a Man-in-the-browser attack. If the tokens are available to JS, then all you need is an XSS attack to steal them.
As I mentioned, using cookies opens you up to CSRF and session-riding attacks, but their impact is limited:
the attacker can only perform an attack when the user has an open session. As soon as the user closes the browser no more data can be stolen (whereas, when an attacker steals a token, they can read data for as long as the token is valid)
the attacker can only perform the same actions that a user can from the front end. This should also be the case for a stolen AT, but in reality, access tokens usually have too broad privileges, and there are APIs you can call with a token that are not normally accessible from the UI.
At Curity we have spent some time researching this and you can have a look at this whitepaper we wrote about the security of SPAs and the pros and cons of different approaches: https://curity.io/resources/documents/single-page-application-security-whitepaper

BFF is considered safer not because of the cookie usage when using the access tokens but because the way of obtaining tokens is more secure. SPAs by definition are not able to keep a secret (in the browser) thus have to use a flow that involves a public client. The BFF allows for a confidential client because the client secret is kept in the backend.
Using PKCE with the public client gives you assurance indeed about the same entity requesting and receiving the tokens, but it give you little assurance about the authenticity of that client. A confidential client takes care of the latter.

Related

Dj rest auth using JWT Token stored in HttpOnly cookies

I'm making a Django Rest Framework application with a JWT authentication with tokens stored in HttpOnly cookies. Authentication is performed via reading the access cookie. I'm using a dj-rest-auth library for this purpose, but I'm a little confused of the security aspect of such method. Knowing that having authentication data stored in cookies can be used to perform CSRF attack, how can one protect their web against such attacks for a specific case I've described above? All cookies are set to be SameSite=Lex.
Do I need to also send X-CSRFTOKEN header obtained from the backend? That would mean that every request to the api will need to have that header. What should be the optimal setup having all those libraries?
The OWASP foundation has created a detailed cheat-sheet on how to prevent from CSRF attacks: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html
Two things worth remembering:
CSRF is a concern only for data-changing requests, so POST/PUT/PATCH/DELETE methods. An attacker performing a CSRF attack can't read the response from the server, so GET requests are not your concern.
The most common way of preventing CSRF is with a csrf token. The server should create the token for the user's session and the token is saved in frontend, but not in a cookie. Then you send that token either in a header or as part of the request body. The server then validates that the token is the same as the one it has for that user session.
If you don't want to persist the token in your server, you can additionally save it in a cookie. So the frontend will keep the token in two places - one in memory/in a hidden form field/etc. and another one in the cookie. Then the server can check if the value from the cookie matches the value from header/body.
All cookies are set to be SameSite=Lex.
Do I need to also send X-CSRFTOKEN header obtained from the backend?
SameSite is not supported by older browsers. As per caniuse, it is supported by 90% browsers in use globally.
Arguments AGAINST implementing CSRF tokens:
I think it's a low risk. If you think your users will be among those 90%, then don't bother with CSRF tokens.
Since you're using JWTs, I assume the frontend is going to be a modern SPA app. If you don't expect it to run on older browsers, then, again, don't bother with CSRF tokens.
Arguments FOR implementing CSRF tokens:
Lax offers no protection on GET requests. You'll have to make sure, today and in future as well, that you never modify server state in GET requests. If you implement CSRF tokens, you'll have one less thing to worry about. Or you can also use SameSite=Strict value.
My opinion:
Personally, I'd just implement CSRF tokens. It's a one time setup and most frameworks already take care of this. So, why not?
P.S.: I'm not sure if you've a typo there, but it is Lax, not Lex.

Why store Refresh Token in a HTTP Only Cookie Prevent From CSRF Attack?

I just read an article from this
https://hasura.io/blog/best-practices-of-using-jwt-with-graphql/
In summary, they recommend to store JWT Access Token in memory (as a variable in JavaScript for example) and Refresh Token in HTTP-Only Cookie.
They said:
But by persisting our session indirectly via a refresh token, we
prevent a direct CSRF vulnerability we would have had with a JWT
token.
But is it store Refresh Token in a HTTP-Only cookie still vulnerable to CSRF Attack? For example, evilsite.com can make request to /refreshtoken endpoint to get new JWT access token. What I understand about HTTP-Only cookie is the cookie can't be read from JavaScript but it will automatically be sent whenever make a HTTP request like how the evilsite.com does. (Correct me if i'm wrong).
Refresh token in a cookie and access token in memory can be a good model if used with care. Hopefully some better guidance will be made available in standards such as BFF-TMI.
The cookie should have these properties and the SameSite property will mean evilsite cannot send it, so that it is good from a CSRF viewpoint.
HTTP Only
Secure
AES256 Encrypted
SameSite=strict
OWASP's CSRF Guidance seems to recommend using both SameSite and CSRF tokens together as the preferred option.
Out of interest here is how I'm implementing things in an SPA Code Sample at the moment - in case it is useful to borrow ideas from:
SPA OAuth Code
Back End API OAuth Code
I may change my mind a little as guidance in this area evolves.
HIGH SECURITY OPTION?
The current concensus is that the following option is preferred in terms of security, though I am hoping risks and mitigations become better documented over the coming year:
Keep access tokens out of the browser completely
Proxy all API calls via the 'back end for front end'
See this insightful 2021 video
This option may add complexity in some areas though, and could also limit capabilities in some scenarios.
As is often the case with security, there are trade-offs with other factors, and the solution chosen may depend on data sensitivity and what stakeholders care about.

Security of storing Bearer token in cookies

My SPA uses React as front end and laravel API as backend.
When the user logs in (via axios and api), the api returns an access (Bearer token) as response. I use the react-cookie framework to store the access token as cookie in the Browser. This cookie will be read and used for any future request.
Is this the right way to do?
Isn't cookie data just something in the Browser that can be easily obtained by any attacker? Since it is just a file one the computer somewhere.
What is stopping an attacker from grabbing that cookie, impersonate as that user and start performing actions that requires authentication?
The token has a life span of lets say 1 year. It will only be refreshed every time the user logs in. I understand that if I set the life span shorter it will be more secure. However that will mean the user would have to log in constantly?
-----Update-----
Im not sure if any of the provided solution answered my question. A SPA app is front end based and the request can be from anywhere such as Postman, Mobile app, or any third party device that wish to talk to my backed server. So those device needs a way to store some access token locally to be used for any future request.
The only way I know this could happen is for my server to send some auth token to the requester and have it store it somewhere to be used for next request.
In this case, Im not sure if CSRF token or any other means would help my concern?
Just like facebook, if I clear my cache, I will have to re-login. That means facebook is storing something on my location computer so I can be automatically authenticated next time
I just want to add some disadvantages of storing tokens in cookies that you should also be aware of:
The max size of a cookie is only 4kb so that may be problematic if
you have many claims attached to the token.
Cookies can be vulnerable to cross-site request forgery (CSRF or
XSRF) attacks. Using a web app framework’s CSRF protection makes
cookies a secure option for storing a JWT. CSRF can also be partially
prevented by checking the HTTP Referer and Origin header. You can
also set the SameSite=strict cookie flag to prevent CSRF attacks.
Can be difficult to implement if the application requires
cross-domain access. Cookies have additional properties (Domain/Path)
that can be modified to allow you to specify where the cookie is
allowed to be sent.
------- Update -----
You can also use cookies to store the auth token, even it is better (at least in my opinion than using local storage, or some session middleware like Redis). And there are some different ways to control the lifetime of a cookie if we put aside the httpOnly and the secure flags:
Cookies can be destroyed after the browser is closed (session
cookies).
Implement a server-side check (typically done for you by
the web framework in use), and you could implement expiration or sliding window expiration.
Cookies can be persistent (not destroyed
after the browser is closed) with an expiration.
Your JS should not have access to the cookie. There are flags you can set on cookies that will help protect them and make sure they are only used for the correct purposes.
The HttpOnly flag is set on the cookie then JS will not be able to access it but it will still be sent with any request.
The SameSite flag will ensure that the cookie is only sent back to the site that gave it to you. Which prevents leakage.
The Secure flag will make it only send the cookie over a secured connection to prevent someone from sniffing it out of your web traffic.
Edit
You might want to lookup an authorization workflow but the gist of it is this:
User logs in with username and password
A JSON web token is issued upon login from the backend and sent to the browser
The JWT(JSON web token) can be stored in a cookie in the Web Storage(Session Storage) on the browser
Subsequent requests to the REST API will have the token embedded in the header or query string for authorization. With that form of authorization, your REST API understands who is making the request and what kind of resource to return based on the level of authorization
Please see #tpopov answer as he also made some really good points.

JSON Web Token expiration and remember me functionality

I am starting to work on an authentication system for an angular 2 Single Page Application using django-rest framework as back-end. I'd also like to have some kind of "remember me" functionality that is going to keep users logged in for a certain amount of time.
From what I have read so far, it seems that the best authentication method for this kind of Angular 2 SPA/REST API is using jwt (json web token). For jwt authentication, I looked at the django-rest-framework-jwt (https://github.com/GetBlimp/django-rest-framework-jwt).
The problem that I see is that the token needs to have a short life span (few minutes to a few hours...) in order to minimize security issues if the token get stolen. The token now needs to be refreshed frequently to avoid the user from being disconnected while using the application. In this case, a "remember me" functionality is posing problem since the token have a short life span.
I thought about a solution involving a second token that would serve as a refresh token. It would be opaque, have a longer life span and would contain information specific to the user (ip address or something like that) so that if it get stolen, the information specific to the user being different would render this refresh token invalid.
So here are my questions:
1- I would like to know if they are existing solutions addressing this problem. As any security/authentication issues, I prefer to rely on well tested solutions to avoid getting my API compromised.
2- Would the refresh token based on specific user infos be a good idea?
3- Any other ideas how I could implement what I want?
For your situation, you really need a way to store issued tokens.
I always use an OAuth2.0 server setup that manages the auth and returns tokens the OAuth setup uses a database to manage everything so it's easy to manage and revoke tokens.
The database schema would be like this http://imgur.com/a/oRbP2 the problem with using just JWT without any management over the issued tokens with long expiration you have that security issue of not being able to revoke easily.
I would advise against including any such thing as a password in the JWT and requiring them to change it what if they use that password everywhere, then they would have to change that everywhere.
Updated from comments
Sessions Authentication use session_id which most the time is stored in a cookie and this is attached to every outgoing request. It is stateful. It is nothing more than a unique identifier that associates a user account that the server has in memory/database. For example, this can course problems when running multiple servers/instances when scaling your infrastructure.
Token Authentication no session is persisted on the server so this means it is stateless. It normally uses the header Authorization: Bearer REPLACE-WITH-TOKEN . This means that this token can be passed to multiple different servers/instances because the authentication is not limited to the server that you initiated the authentication on. This helps with scaling your infrastructure. Tokens can also be passed to other clients.
RESTful API's are stateless so there must not be a session state stored on the server. Instead, it must the handled entirely by the client so that's why token authentication is used.
I had the exact problem when trying to use JWT with an application that needed a lot more than JWT was designed for. OAuth2.0 has a lot more options that I believe are necessary to meet your requirement in the safest manner possible and even features that you may find very useful in the future as your Application may grow and need more features with regards authentication.

Sense of secure cookie over HTTPS

Is there any sense to encrypt cookies (secure cookies) for HTTPS?
As far as I know in HTTPS whole request is encrypted, so do we need additional encryption of cookies?
That depends entirely on your security model. Some reasons why you would still need to encrypt cookies:
Do you care if the user of your application gets the contents of the cookie? In other words, do you store anything there that's internal and shouldn't be disclosed to the user?
Do you care if the user tampers with the contents of the cookie? Encryption can be a way to get integrity protection depending on how you do it. (There are, of course, other ways as well.)
What are the consequences of disclosure of the cookie? If it's a bearer token, whether it's encrypted or not won't make a lot of difference, but if it contains valuable data, encrypting it provides some protection against an attacker gaining access to the browser's stored cookies in some way (whether via a web attack or an attack on the actual system hosting the browser). You still may lose to an attacker in other ways, but it could provide some defense in depth.
The main thing that encrypting the cookie gives you is protection against the user who receives the cookie (or an attacker who can access that user's data), if you need that.