I googled a lot on how to protect the refresh_token from a hacker because it will be stored somewhere in browser's local-storage/cookie, so a hacker can easily steal those tokens and I couldn't able to find a proper answer so I came here.
I understand that access_token will expire in less-time and we should use refresh_token to get a new access_token. But if the hackers steal the refresh_token means, he can stay as a login user for a long time, right?
Some people are saying, you can protect it using client_id and client_secret, but the hacker is going to access the endpoint of the API, which has the client_id and client_secret. So again, a hacker can get a new access_token easily.
So I am finding no way to protect the hacker from getting the new access_token.
Can someone able to guide me here, on how I protect the hacker from getting access to refresh token from browser's local-storage/cookie?
From the context of your explanation, you are talking about a browser based application. If this application is one that does not have a backend, then you do not have a secure place to store your long-lived tokens or client secrets.
From OAuth 2.0 perspective, these are called public clients. Thus protocol do not allow them to have a client secret. So they have a client ID and a redirect URL for client authentication (client identification). Implicit flow is one key flow suitable for SPA that runs on browser. By specification, they will not get a refresh token. Reason is their inability to protect such secrets.
But if you have a backend and have the ability to correlate browser session and backend storage, you can use a flow that gives your a refresh token and store it securely. But this require your application architecture to support such (ex:- Browser session and backend storage).
Also, rather than making end user to login every time, you may use the identity server's logged in state to skip log in. This too will rely on identity server's browser cookie and it's life time. For example identity server may have a browser session valid for 24hours. So your client will not see log in page when accessed thew application within the time.
You can try to secure the local storage using this library Secure-ls
Related
I'm creating a REST API to store some information about some items.
It is nothing highly sensitive or anything but I still want to properly secure it. Also in regards of maybe having to secure something else in the future.
To sign the users in I'm using OIDC with Google and Azure to retrieve user information from the user information endpoint. After that I want to store the user in a database along with their permissions. For them to access the API I want to generate and sign a JWT Access Token and Refresh Token. So far so good.
I want the acces to the API to be stateless (with the Access Token) for scalability. I'm not so much worried about the sign in process being stateless. The refreshing of Access Tokens via the Refresh Token also doesn't have to be stateless, but it would be nice to have.
I was reading through some other questions and articles online regarding XSS and CSRF. To me it all boiled down to two things:
Don't use local or session storage to prevent XSS-Attacks grabbing tokens stored there. Solution seemed to be to use cookies (http only cookies, samesite).
Don't use cookies as to prevent CSRF.
I'm now kind of stuck because the two options seem to recommend not using either.
I thought about how this might be solvable and was reading through OWASP recommendations mentioning generating a fingerprint during sign in and storing it in the JWT as user context.
In my mind I have the following process.
Sign the user in using OIDC and receive information about the user from the user endpoint.
Look up the user in the database and get their permissions.
Create a unique fingerprint for the user.
Store the fingerprint in a hardened cookie (http only, secure, samesite).
Create a JWT Access Token using the users id, permissions and an encrypted string of the fingerprint.
Create a JWT Refresh Token using the users id, permissions and an encrypted string of the fingerprint.
Sign both JWTs.
Return the Tokens to the client with the hardened cookie set.
Now if the user wants to access a protected resource he sets the Authorization Header with the Access Token and sends the request, which will then also include the hardened cookie. The server can decrypt the fingerprint from the Access Token and compare it to the fingerprint from the cookie.
If the user wants to use the Refresh Token to get an expired Access Token the fingerprint would also be validated before issuing a new Access Token.
Access Tokens would be short lived e.g. 15 minutes. Refresh Tokens would be long lived e.g. 1 day.
In my mind this solves both problems:
Leaking of the tokens would be useless without also having the fingerprint from the cookie or the cookie itself.
Leaking the cookie via something like CSRF would be useless as the Tokens would not be available.
Only if an attacker would simultaneously get hold of both he would be able to have access.
My questions are:
Am I overlooking something?
What would be a good way to generate this fingerprint? Use the "sub" from the user endpoint?
Thanks for your help already!
I am learning about different Oauth2 flows but it does not provide any guidelines on securely persisting different kinds of access tokens in different scenarios and I could not find relevant information on the topic by Google-fu.
I am wondering if is it safe to save access tokens in a secure frontend context like httpOnly cookie and optionally directly calling the api from the browser without proxying it through the application server?
It appears more secure to me because access tokens unlike passwords cannot be hashed, the means to recover all access tokens (if encrypted) must exist on the server otherwise it would not be able to call the service on behalf of the user. So, were the application server compromised so would the access tokens of all users.
Am I missing some context here or is it correct?
If you think about sharing your own access token with some users user agent (browser), then this solution is never secure. The user agent (browser) is something working totally on behalf of the user. The user, if he wants to, may have access to any kind of resource the user agent operates with. Sharing a token with the user agent is like sharing the token with the user himself.
Whichever method you choose, you need to ensure your backend verifies the token (e.g jwt).
You probably wouldn't need to verify a secure cookie because a secure cookie cannot be accessed/modified by the browser.
I have been keeping my 3 legged auth tokens and the refresh token in cookies so then I can transfer them after reload. I am on localhost so I didn't have to think about security but soon enough I will be putting my web application on the internet. I know that you should only have a token with viewables:read as the only scope to prevent any snooping of the user's data. Can it be safe if I encrypt the token with my own encryption method or should I keep the token in a mySQL session on the server side? If I should make mySQL session, can someone give me a link to a tutorial on the mySQL session parser npm extension? I haven't got it to work in the past. Thanks.
If you have a 3-legged token that will give access only to that user data. If that token is viewables:read the user will be able to view his/her models, nothing else. You can use proxy on Viewer to avoid sending it to the client, see a NodeJS sample.
The refresh token is useless to that user, to actually refresh it the ID & secret are required (and the secret should be hidden, the ID can be exposed for BIM 360 provisioning, for instance).
Assuming the browser is not compromised and your cookie is configured to use only https, then the cookie is only exposed to the website that created it and protected during transfer.
I use cookie-session on my sample apps, like this.
I know there are already many posts about Oauth, Oauth2, JWT, etc.. I have read many and I more confused than ever so I am looking for some clarification. I will propose my view on the subject and I hope somebody can tell me if my implementation is secure enough or what I am doing wrong and how to improve it.
I am building an API Rest server for serving my resources to my users. Let's suppose it is a bank app where users can deposit, withdraw and transfer money.
I am using nodejs, hapijs, jsonwebtokens, and bcrypt for my server. I want to implement two token authentication flow (Oauth2).
This is the way I am doing it:
User logs in to the auth server by giving some credentials (username and password).
The server verifies the user's credentials, if they are valid, it will grant access to the user and return a refresh token and an access token.
These tokens are saved into the local storage of the browser or mobile device.
The access token:
is signed as a jsonwebtoken.
contains issued date, expiration date (5 min), user data (id, username).
The refresh token:
is signed as a jsonwebtoken and encrypted with bcrypt.
contains a unique identifier
may contain an expiration date
is saved in the database.
As long as the access token is valid, that means, it has not expired and contains valid user data, the resource server serves the user the requested resources.
When the access token is no longer valid, the auth server requests the client to provide a refresh token in order to issue a new access token
The server receives the refresh token from the user, decrypts it, compares it to the one in the database, checks if it has been revoked, and checks its unique identifier.
If the refresh token passes all tests, the server issues a new access token to the client.
If the refresh token fails one test, the server requests the user to re-authenticate.
Notes: I am trying to avoid the usage of cookies.
Questions:
If the user is able to steal an access token, I guess it can also steal the refresh token. So, how can I make the refresh token more secure?
Is my perspective of the Oauth2 flow correct?
What can I improve?
Am I missing something?
The reason OAuth2 is so confusion to many people is because it uses different authentication flows depending on what kind of client is used.
OAuth2 distinguishes two client type, confidential or public. Next to that, there are 2 grant flows that are redirection based (auth code and implicit) which are meant to be used with a browser or browser control.
The other two flows (resource owner password and client credentials) are meant to be used from non-browser apps (CLI, background services, trusted mobile clients).
I've described the different flows and when to use them in more detail in this answer here.
How can you provide example for refresh node js auth token? I mean by what the parameters can I refresh auth token? For example if I can refresh it by login and password then where should I store this params for single-page app? As I understand store it in cookie is not good idea for security, localstorage is not good also because some of browsers not supported it. So maybe someone know another way for refresh token?
Cookies are a very secure storage mechanism, if used correctly. Local storage should never be used for authentication information. OWASP has a great write-up on storage security:
https://www.owasp.org/index.php/HTML5_Security_Cheat_Sheet#Storage_APIs
To quote the important parts:
Do not store session identifiers in local storage as the data is always accessible by JavaScript. Cookies can mitigate this risk using the httpOnly flag.
[With local storage] There is no way to restrict the visibility of an object to a specific path like with the attribute path of HTTP Cookies, every object is shared within an origin and protected with the Same Origin Policy. Avoid host multiple applications on the same origin, all of them would share the same localStorage object, use different subdomains instead.
Back to your original question: where to store the refresh token? Answer: In a HttpOnly cookie. This prevents the cookie from being stolen by XSS attacks, and it makes it very easy for your server to issue new access tokens (using the refresh token) because the server will have access to both at the same time, on the same request.
You can add another layer and encrypt the entire refresh token that is stored in the cookie.
Caution: when using cookies, you also need to protect yourself against CSRF attacks
I’ve written at length about front-end security and JWTs in these two blog posts:
Token Based Authentication for Single Page Apps (SPAs)
https://stormpath.com/blog/build-secure-user-interfaces-using-jwts/
Disclaimer : I work at Stormpath, our service gives you a secure, hosted user database with many features. Our express-stormpath module makes it very easy to get started with login and registration flows for your application. We are in the process of writing a new release, and it will be using access tokens in the way that I describe in this answer.
I created AuthToken model that contain these fields:
user_id, access_token, refresh_token, access_token_expiration
After successful user login, server side will send refresh_token and access_token to client side and store it to localstorage(cookies for old browsers).
And all subsequent requests will be sent with access_token(I use header x-access-token for $httpProvider in angular).
When token expires, client needs to send refresh_token for updating access_token, refresh_token and expiration date. Since I use sockets I can refresh access_token if it is expired in any request(for this I send z-refresh-token header also for each request) so I shouldn't send any extra request and I can keep current user request, just will return tokens via socket event after it was updated.
Hope this helps