Just a general question.
If I'm setting any sort of authentication cookie, token or sessionid via a backend to one's browser, how do I prevent a user from reading that and then giving that to another user to use on their browser to access the backend?
Related
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 am developing Django + React project and I'm caught with this security approach concerning login and managing views for the logged in user.
I am using django-rest-framework or DRF for my RESTful API. And I'm using django-rest-knox for authenticating user logins since I am implementing Token-based authentication (instead of session-based which uses CSRF).
Question: Is it a good idea to save user's id and token in local storage?
Currently, I have a /auth/login/ API endpoint that handles the backend logic of logging in user and returns JSON response of login details upon successful login (including user id and token).
In my frontend, I use redux and redux-persist so the user's login details are kept even when the site is refreshed. The way redux-persist do it is that it saves the response in local storage. This means that the user id and token can be accessed and changed anytime thru dev tools.
If user will then make a POST request to an API that requires a Token authentication header, the frontend will look into that local storage for the token value to be supplied to the request header.
If user will then make a POST request to an API where the user id is required in the request data, the frontend will also look for the id in the local storage.
Localstorage is not safe, especially for storing tokens and ids. Any user can go to the browser's developer tools, see and also edit its contents, for example.
You could check on Django's sessions, so you can store data securely at server side and keep its contents associated with a specific user. There is a great tutorial at Mozilla that explains sessions in a clearer way than the official documentation.
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.
I have been reading about csrf and fiddliN around with implementing it using go and gorilla toolkit. I am also using gorilla sessions which i have implemented to store a user id in an encrypted cookie.
the cookie is decrypted and i fetch the user from the db with the now unencrypted key-value store using a middleware I wrote...
if the user is creating the session cookie from authentication through an oauth2 provider, do i have any need to implement csrf protection if all the views that need such protection are only allowed to authed users anyway?
Suppose a user has logged into your site, and has continued to browse the Internet in the same session. They stumble across another site which is maliciously targeting yours, with HTML or JS that causes the user's browser to make a request to an endpoint on your site. This will contain the user's session cookie for your domain, and succeed unless protected by a CSRF token.