Although there are many posts about this topic (or closely related) on SO, I did not find what I am looking for.
As the title suggests I am using Django Rest Framework as a backend, and React as a frontend.
Now I implemented token authentication, and it works perfeclty. The only problem is that the token is stored in React's state, and if the user refreshes the page, he is no longer logged in (the token is lost).
So, now I want to switch to session authentication, since the problem is solved then. But that will require me to do some research, and before I go there I'd like to know if that is the best choice.
My question:
Do I need to use session authentication to have users stay logged in, even when the React's state changes. Or can I also achieve the same thing with token authentication (in a safe and responsible way?)
I figure I can save the token in a cookie, but that doesn't seem safe to me.
EDIT:
Later I realized, why not just store the token in a session?
SessionAuthentication would be the most straightforward way to achieve what you want. The configuration is described at http://www.django-rest-framework.org/api-guide/authentication/#setting-the-authentication-scheme This will set a session id in a cookie that is handled by the browser.
Alternatively you can store a token in the browser's cookie but that is vulnerable to XSS attacks and other javascript attacks. For more security you can store the token in an HttpOnly cookie. The cookie would be persisted across tab/window closes by the browser.
Also to clarify cookie handling is built into most browsers. Your react state is in userland and lives in a different memoryspace than cookie storage.
More info:
Ask HN: Cookies vs. JWT vs. OAuth
https://developer.okta.com/blog/2017/08/17/why-jwts-suck-as-session-tokens
http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/
Related
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.
I am implementing authentication in Django using SimpleJWT, and have a few questions regarding the same. To give some background I have multiple domains with my backend, some with normal login (username and password), and some with SSO logins.
Question 2:
Suppose, I store the access tokens in local storage and send the access token to all APIs, and I'm also refreshing it before it expires. But what will happen if the user closes the browser, and we are not able to refresh the access token. The access token expires and the user gets logged out. How can we keep the user logged in for a certain amount of time (say 30 days)?
When the Access token expires, you use the Refresh token to obtain a new Access token.
This works because Refresh token has a long life, typically up to 30 days (but can be even longer if you want).
Example:
User closes browser
Comes back 10 days later
User sends a request to the server
Server will return 401 Unauthorized response because Access token has expired
Your app will send a request to obtain a new Access token using the Refresh token
If the Refresh token is valid, server will return a new Access token
If the Refresh token is expired, server will return a 401 response. That means user needs to login again.
Security considerations
Personally, I think JWT for most web apps is not an suitable idea because of conflicting opinions and advice on how to securely store the tokens.
Since a Refresh token is really powerful, it is not advised to store it in the browser. So where do you store it? And that's when this misleading idea of "backendless" web services powered by JWT starts to fall apart.
Paradoxes regarding storing tokens:
Store it in localstorage: Vulnerable to XSS attacks.
This is really serious because the XSS vulnerabilities can also come from third party JS libraries, not just from your own code. Hackers can hijack a third-party library on NPM to inject malicious code and you might be unknowingly using it in your project (it might be a dependency of a dependency of another dependency...).
Store it in httponly cookies: Safe from XSS attacks but requires a first-party backend server (because third-party auth servers can't set cookies for another domain).
If you stop to think about it, you'll notice that this case is exactly similar to the regular session auth where a session token is saved in the cookie. So why not just use session auth instead of this complicated JWT setup?
I'm going to advise you to thoroughly research this and decide whether you really need JWT for your web apps.
JWT auth using cross-origin cookies
Since you mention that your frontend apps connect to an API server in another domain, using JWT seems alright.
If you control the API server, you can setup CORS headers to allow the API server to set cookies on your apps' domains.
Important:
Since this involves Cookies, it is vulnerable to CSRF attacks. But > that is easier to prevent using CSRF tokens.
That means, with every POST request, you'll need to send CSRF token
and the API server must also validate that CSRF token
Here's a diagram I make of the auth flow in that case:
For Question 2, add this code on your settings.py file
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(days=30),
'REFRESH_TOKEN_LIFETIME': timedelta(days=30),
}
I'm building an application with django , Drf and currently using vanilla JS as Frontend for now.
I searched almost all through web on different use case for authentication on the web and I found out different links but these links seem to always favour the session authentication and token authentication.
Using Django helps us with the session authentication as default so I decided to study the auth process using a token auth.
While doing this, I initially used the localstorage as a store for my tokens gotten from the backend response after user authenticates, But for some reasons which are valid , most devs/engineers advise against using the localstorage as it prones one to xss attacks..
So I decided to implement the httponly cookie method, but I haven't seen a practical use of this done on Django, I've seen theories on implementing all these but haven't seen someone done this..
Please how can I use the httponly cookie with my token stored as a cookie with DJANGO
EDIT
I know a httponly cookie does not allow JavaScript to access a cookie, so I decided to do this.
Django sends the cookie httponly with the token as the cookie
User makes a request to the backend
server gets the token from the cookie sent as a request from the backend.
4)"where the problem now comes" I can't set the token as an header in Django, I tried using the request.headers['Autho...] = Token ....
But that doesn't allow item assignment..
So if my logic is correct this is where I'm stucked
EDIT So this time, I am now able to add a header from the server , using request.META to pass an Authorization key with the Token .... Value, that seems to work fine instead of having to use request.headers for passing an assignment..
But something happened which shocked me, in as much as I'm able to change or add an authorization token from the server , the view still gives me an error, much like I never passed a token at all.....
It's like after the whole efforts and everything nothing still changes, except if it's requested from the client side 😢.
Guess I will have to stick with localstorage for now, but still research more or wait for answers .
I've done the Authentication with token using httponly cookie..
I recalled when I asked questions and some loving guys from here helped tho, we couldn't see a straight off answer as we had to research and think as well...
The steps I used was this.
Django takes in user credentials
Django authenticate that credentials
a token is exchanged for that data
we set the token to a cookie using
set_cookie(.... , httponly=True)
** Then it was now time for the real workout .
I created a middleware which will be responsible for setting the token to an Authorization key in header dict.. instead of allowing the client to do this.
---- The client couldn't handle this coz it was now a httponly flag which will prevent js from accessing it as the purpose of using httponly was for this to prevent xss attacks when tokens/cookies are normally stored in a browser storage
we then handle the middleware to our taste, as in mine I tried making sure it work for only some views and not all views (will be planning on making a custom decorator for it)
then last was to 🤔🤔 we'll have fun and smile at seeing me create something as such without a previous tutorial...
The GitHub repo link https://github.com/HarryAustin/tweeter-DrfTest-httonlycookie
I know the concept of OAuth2 and OpenID. in our application authentication is happening through OKTA and we receive access-token in a response.
Our architecture is a microservice-architecture and we are using EmberJS at frontend.
we have to implement remember-me functionality it will keep the user logged in for the next 30 days.
I did some study on it and came to points that will satisfy my requirements.
keep user session active for 30 days in OKTA.
refresh access token periodically based on its expiry time.
How this refreshing will work if browser is closed?
Let's say a user is logged in and closed the browser then reopened it after 3 days.
With respective to OAuth 2.0 best practices, it is recommended to have short lived access tokens. There is a dedicated RFC definition such best practices which is identified by RFC6819 - OAuth 2.0 Threat Model and Security Considerations. There are several sections which emphasise on using short lived access tokens .For example here you can see why it is recommended.
With this perspective, you may handle this situation using browser cookies. Cookies are the mechanism which helps browser and server to maintain states. In a typical web application, login state can be maintained through cookies. There are two variants of cookies.
Session cookie
Persisted cookie
The second cookie type, persisted cookies do not go out of browser when browser is closed. Of course user can clear cookies to remove them. In your scenario, you can set such a cookie to user with desired lifetime. In the backend, you need to map cookie value to a state, which should start when backend receive a valid access token/ ID Token (after authentication and authorization step).
About cookies security, there are many things you must concentrate on. But the most important are setting cookie to be secure and HttpOnly.
Also, you may store a reference to refresh token in backend correlating to the cookie. Then for each fresh usage you can use refresh token to obtain access token if you require for example API access with access token.
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.