I want to see if I can accomplish preventing CSRF while not having to store any additional information in a users session in redis on the server. Upon requesting the form to delete an account, can I sign a JWT token using a random string (uuid4) and secret also with an expiration time and send the result to the client. When the form is submitted I will verify the JWT.
Something like this:
const tokenToSend = jwt.sign(uuid4(), SECRET, { expire: 60 })
A simple way to describe Csrf attack is that the victim (who has login a vulnerable website A) browser a third webside B which did a request pretented as the victim to website A.
So to prevent csrf attack, we have to set the requests (that we want to protect) not predictable so that the attacker can't prepare the requests before. If you use jwt as csrf token you have to make this jwt unique for every request.
Related
I am using jwt. I have some admin routes. I save the token in localStorage. In the payload of my token i have also admin property which is true or false. I wonder what if the 'admin' token from some user is stolen, and the old 'non-admin' token in the localStorage from the malicious user is replaced with the 'admin' token, then he will have access to the admin routes.
To prevent this on some way:
I will refresh the token on 10 minutes for example ( but the malicious user can do a lot of bad thinkgs in that 10 minutes - delete users from DB, delete configurations etc...).
Is there any other way to prevent and this 10 minutes 'possible attack'
Save the token in httpOnly and secure cookie. Is 100% sure that if i store my token in this kind of cookie, and nobody can edit it ? so when the 'admin' token is stolen the malicous user can't just copy paste the new token, like he could in localStorage ?
Don't save the token in LocalStorage since it is accessible to js, which means any XSS attack will have an access to the token.
Use 2 kind of tokens,
Short term access token (10 mins), it will be attached to each api request, it must contain something that is none "guess"ible some kind of hash, with it you will identify the user on the server side, it will be saved in memory.
Long term refresh token (12 hours or more), it will be saved in httpOnly + secure cookie. It has one purpose, with it your app can generated a new access token (when it expires). It must contain none "guess"ible hash to identify a user.
This will make your system much robust. If someone get somehow the accessToken, it will be expired in 10 mins, without it your api will refuse requests.
It is much harder to steal httpOnly + secure cookie, if someone managed to steal it, you can "revoke" the hash inside the token, so, it will become useless.
By revoking, it is simple as generate new hash in the db for the specific user/ entire db.
I always recommend to read this https://hasura.io/blog/best-practices-of-using-jwt-with-graphql/
The entire idea on accessToken + refreshToken is explain there.
Some my code example, Axios Interceptor Response Token Refresh API called but getting Token is expired regardless in refreshToken API & lator all APIs
I have read a few articles regarding JWT refresh tokens, and how/why they are used. One thing i have seen mentioned here: https://hasura.io/blog/best-practices-of-using-jwt-with-graphql/#persistance and here: https://dev.to/cotter/localstorage-vs-cookies-all-you-need-to-know-about-storing-jwt-tokens-securely-in-the-front-end-15id
is that using refresh tokens mitigates against CSRF attacks. The first article states:
The refresh token is sent by the auth server to the client as an HttpOnly cookie and is automatically sent by the browser in a /refresh_token API call.
Because client side Javascript can't read or steal an HttpOnly cookie, this is a little better at mitigating XSS than persisting it as a normal cookie or in localstorage.
This approach is also safe from CSRF attacks, because even though a form submit attack can make a /refresh_token API call, the attacker cannot get the new JWT token value that is returned.
The second article says something similar:
Although a form submit to /refresh_token will work and a new access token will be returned, the attacker can't read the response if they're using an HTML form
I am struggling to see how this would prevent CSRF attacks as I am thinking the following:
A request to /refresh token from another domain to the users will return new JWT token to the user. I am going to assume this is stored in a HttpOnly cookie (as is done in the first article)
As CSRF does not involve any injection of javascript and the cookie it httpOnly, the attacker can't read the value of the new JWT token.
However, if the JWT token is stored in a cookie again, surely a CSRF attacker can just send another request using this new cookie, with the new JWT token sinde?
If my understanding is correct, I am struggling to see how CSRF attacks are prevented by using refresh tokens. Can someone please explain exactly why refresh tokens prevent CSRF attacks, and why the CSRF attacker can't just use the new JWT the user would receive for future attacks?
It seems to me that the thing that would actually be preventing a CSRF attack would be the use of a sameSite cookie, or maybe using some sort of anti-forgery token.
The new jwt would not be returned from the identity provider as a cookie. That would not make much sense as the client on a different origin would not be able to read it. Instead, the token is passed in the response body, or even the url (usually not the token in that case, but let's not delve into that).
So the idp has its httpOnly cookie to authenticate the user, issues a new token in some way that is not a cookie, and the client stores the token for the appropriate origin (not the idp) in say localstorage. This way, any call to the resource server is not vulnerable to csrf, because the token needs to be explicitly be added from localstorage. The idp can be called by attacker.com to issue a new token ("csrf"), but attacker.com will not have access to the token due to the same origin policy, so it's not exploitable.
Note that even if the new token is returned as a cookie for the idp and read from there by the client, it's still ok, because the idp will do nothing with that token, and the resource server (~api) will not receive it automatically.
1. User will do the login UserName and password.
2. If the login success then server will return JWT.
3. Now we will store the token.
4. Now for every request we will send the JWT Token for authentication on server.
My question is that Where can we store the JWT token because Local storage,Session,Cookies is not safe.
"Only the server should know the "secret" that is used to generate the JWT. If someone modifies the data contained in the JWT, the server will fail to decode it. So the server can trust any JWT that it can decode."
You don't need to store JWT token where someone can't find. And if you think if hackers get token of someone, there is a expiration date option for this.
Check this: How safe is JWT?
httpOnly cookie
It's a special kind of cookie that’s only sent in HTTP requests to the server, and it’s never accessible (both for reading or writing) from JavaScript running in the browser.
Check this:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies
You can use this Package to make your life easier if you want:
https://www.npmjs.com/package/react-cookie
This article suggests that we should be changing our CSRF tokens on every request to prevent a BREACH attack. i.e., if we use gzip/brotli and per-session CSRF tokens, and SSL, our tokens are vulnerable with only 1000 requests.
Supposing that's true, how would one go about regenerating a CSRF token on every request without breaking back/forward and multiple tabs?
The obvious solution is to store an array of valid CSRF tokens in our session instead of just the most recent one, perhaps limiting it to 100 or so.
But what if we used a JWT or something instead? We could store just the user ID in there, then validate that the token isn't expired and it belongs to the current user, and we wouldn't need to store it on the server at all. The only problem is that we couldn't revoke the CSRF-JWT when the user logs out, which would necessitate a short expiry, but we wouldn't want it too short or it'd expire before the user has a chance to submit the form.
What's the best way to approach this problem?
You can use a JWT and send it as a Bearer token in the header and store it in local storage. Do NOT send it in a cookie. Send it on every request and check the validity of it on every request. You can give the user a refresh token that you can revoke when they log out. The refresh token will generate access JWTs that expire after a very short period for each call.
You can use the JWT for access control and all your authorization needs.
I am trying to implement json web token for my user authentication using jsonwebtoken and express-jwt in my expressjs, nodejs and angularjs app. I read various articles and tutorials and now I am a little confused about something.
First of what I understood about JWT is it is composed of three parts separated by period:
Header: Describes the jwt and the algorithm.
Payload: Contains the information:issuer, audience, expiry
Signature: signature based on header and payload
So every request is made with the token, which is validated at server. According to this article, issuer is the one who makes request. In case of user authentication, user is the issuer. Now using express-jwt middleware, validated the token in request header and attaches the decoded token to req.user:
app.use(expressJwt({ secret: jwtSecret }).unless({ path: [ '/login' ]}));
How long can be the length of payload? And how and where do I save token on client side so my session persists even after browser closes, unless the user logs out, like facebook's "keep logged in"? Because I dont want the user to be prompted to log in again if the token expires, I want the token to renew unless the user logs out.
You may store JWT in a persistent cookie or browser local storage. The length of the payload is not limited by the JWT itself but by the storage. Remember that long tokens may add significant load to your requests or might need extra server configuration to allow extra long HTTP headers.
If you do not want JWT tokens to expire, set the expiration time accordingly when issuing them. This is an additional security risk if JWT leaks as user has no way to revoke them.