I'm using JWT for user login/signup and I had a question about sending/receiving the token.
Currently, I'm storing the token as a property in a JSON Object starting in the server, then I send it to the front-end. After the client receives the object it stores the token as a cookie. Every POST request from the client to the server will have a token property in it's body, and the response from the server will have the token as a property also.
Is this okay, or should I be sending the token as a header in the requests/responses?
Using: React (+DOM), JavaScript, Express, Node.js
Storing JWT token in Cookie is good enough. You don't need to send to token in the request body or return in response.
Good practice
Store JWT in cookie with mode http-only and is-secure: true so javascript can't see this token, and only transfer the token using https security layer.
Add a custom request header in every ajax request and verify this header in backend to advoid crsf attack.
Hey guys coming back to this post to add some more information for those who are in the same situation I was.
When using fetch to send requests to your backend, make sure you add
credentials: 'same-origin'
to your fetch options object in order to send/receive cookies to/from the server.
I used cookieParser in node backend code to send/receive cookies. Make sure to at least make them http-only and include any other security options you need or want.
Related
Long winded but I'm using Googles Youtube v3 Data API node.js package to sign in users and view playlists and such. Currently when a user successfully logs in with googles Oauth redirect flow a route server side is called which passes in a code by url query parameters. I'm able to parse that out, generate a token with my oauth2Client and then create a signed jwt. Right now I redirect the user to a url that has the signed jwt as a url query parameter which is then parsed out browser side and stored as a token in the local storage, this is my first time using anything related to jwts and want to be certain that I am doing things in a secure way. Being such I'm not entirely sure that how I am sending the token server side to client side is the proper way and not quite sure where to start looking.
You can pass in response like res.cookie(key, value)
There are multiple way to pass token from server side to client side
1) you can pass token in your response
2) you can pass token in response header
It is not the right way. If the server is responding to an XHR request (coming from javascript), then the server can send the JWT in the body of the response. If the server is responding a regular browser request (GET or POST, but not handled by javascript), then it's easier to just put the JWT in a cookie.
There is Spring MVC application - the server produces HTML, the client is not SPA (i.e. this is not about API in any form).
During authentication JWT token is generated and returned to the client. During authorization the server verifies JWT token.
How to store JWT token on client side and pass it via all further requests to the server? Remember this is Spring MVC application and not SPA.
I tried to google for any examples but the only findings relate to REST authentication, that doesn't relate to this case at all.
In worst case we can perform authentication from JavaScript and store JWT token in cache/cookie. But maybe Spring MVC supports this out of the box and we need just to set some checkbox in configuration :-)
For non-SPAs, the usual approach is to store the authentication token in the server session. When the client makes a request, the appropriate session is retrieved via the JSESSIONID cookie (or the JSESSIONID is added to the URL if cookies are disabled).
I'm not sure why you can't use the approach above, but if you want to store the JWT on the client, a common approach is:
store the token in the browser's local or session storage when it's generated, e.g. window.sessionStorage.authToken = 'token_value';
add the token to each subsequent request by setting the Authorization HTTP header to the value of the token
when the user logs out, delete the token from browser storage
I can use "Set-Cookie" header with JWT token from server side. The client will interpret this header as setting a cookie automatically. In this case passing the token to every requests will be done without additional steps from client side.
Some details are described here https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage
I will use this as an accepted answer until a better option provided.
I have a React app with backend API written in Express (all /api calls are proxied there).
Upon successful user authentication, I will be generating a session ID and storing it somewhere on the client side so that I can later authorise requests to the API.
What is the best practice of implementing this architecture on the Express side? Shall I just send the session ID along with the body of each API request and then precede all backend calls with an authorisation mechanism? Or is there some better/easier way of doing this?
My intuition would be to take two steps.
On the client, set up your HTTP client to pass the sessionID as a header. You can set custom headers using an HTTP client like axios or, in ES6, fetch, and apply those headers to every request send to your Express API.
Set up a middleware function on your app that will run on every request received by the server. Express has an easy way to do this using app.all("*", yourAuthFunction). You can also take a look at app.use for applying a middleware to more specific routes. This will ensure that your sessionID gets verified on the server before any data is sent in response to the client. Of course, you'll have to write the auth function to work how you'd like.
Good luck!
When the user successfully authenticated (it should auth' anytime the page loads), a response should be sent to it (contains the session token).
Every other request should be authenticated with the session token that received on the authentication response.
You can store this token value into hidden input <input name="session" type="hidden" />
I am still not clear in regards to the JWT and CSRF working together. I understand the fundamentals for the JWT (what it is and how it works). And I also understand the CSRF when used with sessions. Similarly I understand that there are risks involved with storing the JWT in localStorage and that's why you need the csrf token. So my question is, how do I use them both. For simplicity say that I have a login page.
1) I have the user signing in and once the email and password are consumed if the user is authenticated the server will send a CSRF and will store a httpOnly cookie with the JWT (how do I set the cookie using PHP). What I understood is that you can use header('Set-Cookie: X-Auth-Token=token_value; Secure; HttpOnly;');please confirm if thats the way to do it.
2) Once I have set the cookie with the JWT. How I am sending the CSRF token with subsequent requests> From what I understood, you set them in the headers. So if I am making an Ajax request I will put them in the headers.
3) Once the request is made and the CSRF token is sent along with the request. How is the validation made. What am I comparing?
Last, is this safe to implement!
I would highly appreciate if you could include as much details as possible.
One approach that I've seen and used myself is to include the CSRF token inside the JWT as a claim. So when the user sends username and password, you can do the following:
If username and password are correct, proceed with the following listing.
Create a new JWT and include a generated CSRF token in the payload as a claim, then sign the JWT.
Respond to client's authentication request by setting an HTTPOnly cookie which contains the JWT. This ensures that only the browser (not the client side app and possibly malicious scripts) has access to the JWT. It's also a good idea to set the cookie to secure. This prevents the browser from sending the cookie if an unsecured communication channel is used (i.e. not https).
When setting the JWT cookie, you should also set an HTTP header which will also contain your generated CSRF token. Note that now you will have the CSRF token in two places—inside the JWT cookie and in an HTTP header.
In your client app, store the CSRF token from the header into localstorage.
For each request, take the CSRF token from localstorage and include it as a request header (the cookie containing the JWT is passed along automatically by the browser).
The server should read the JWT from the cookie, validate its signature and read the CSRF token from the JWT's payload. Then it should compare it against the CSRF token that's in the request header. If they match, the server can continue processing the request.
I suggest you to watch this talk about JWTs. It goes into more details about the same approach (also with nice diagrams). Feel free to watch the entire talk or if you're interested specifically in CSRF, start from 36:29.
The following is a slide (from the presentation linked above) that demonstrates how JWT and CSRF tokens could be used together. I annotated it with red numbers which correspond to the listing above.
The common paradigm to defend against CSRF it to generate a token for each "form", and validate that the token that was set for the specific form is correct.
That way, attacker can't guess the token therefore can't make an external form that sends to your server.
Usually, the method to set that token is via Cookie and the client app will attach it to some custom header, that will give you an additional protection, then, the server should compare between the cookie value and the header value.
It is important that the token will be valid only for one session, otherwise, an attacker can reuse the same token that he got in the attack vector.
JWT, is a method to authenticate the user to the system not to validate that the request was valid.
I will try to explain by example, assume you are didn't implemented any protection against CSRF, but you do have a mechanism to authenticate your users (with usage of JWT), so the user logged in with the correct user & pass, your server will send a JWT, the client will save it to localStorage / memory.
Now, the attacker can craft a form on his site that will point to your server, assume that he knows the users JWT token (he got it with other methods like MITM), all he needs to do is to trick the user into going his page with the form, and the form will be sent to you with any problem, your server will accept the request and the attack will succeed.
If you implement any CSRF mechanism, the attacker at the example will not be able to guess the current token, therefore your server will ignore his request.
I want to bring a doubt about JWT tokens and CSRF from the Stormpath post that explain the advantages and disadvantages of storing the JWT either in localStorage or cookies.
[...] if you are reading values out of a cookie using JS, that means you
can't set the Httponly flag on the cookie, so now any JS on your site
can read it, thus making it the exact same security-level as storing
something in localStorage.
I'm trying to understand why they recommend adding the xsrfToken to
the JWT. Doesn't storing your JWT in the cookie and then extracting it
out and placing the JWT in the HTTP header and authenticating the
request based on the HTTP header accomplish the same thing as
Angular's X-XSRF-TOKEN? No other domain could make requests on a
user's behalf if you authenticate based on the JWT in the header,
since other domains cannot extract the JWT from the cookie. I don't
understand the purpose of the xsrfToken in the JWT - perhaps its just
an additional layer of defense - meaning that attackers would have to
have a compromised script on your site and CSRF a user at the time. So
they'd have to hit you in both ways to be able to pull of an attack.
The post is linked in this answer where says:
The last thing is to ensure that you have CSRF protection on every
HTTP request to ensure that external domains initiating requests to
your site cannot function.
[...] Then, on every request into your server, ensure that your own
JavaScript code reads the cookie value and sets this in a custom
header, e.g. X-CSRF-Token and verify that value on every request in
the server. External domain clients cannot set custom headers for
requests to your domain unless the external client gets authorization
via an HTTP Options request, so any attempt at a CSRF attack (e.g. in
an IFrame, whatever) will fail for them.
Even if they could set custom headers, they couldn't access the cookie where the JWT token is stored because only JavaScript that runs on the same domain can read the cookie.
The only way they could is via XSS, but having an xsrfToken in the JWT is compromised too if exists XSS vulnerabilities because a malicious script running in the trusted client domain could access the JWT in the cookie and include a header in the request with the xsrfToken.
So the equation should be:
TLS + JWT stored in secure cookie + JWT in request header + No XSS vulnerabilities.
If the client and server are running in different domains, the server should send the JWT and the client should create the cookie with the JWT.
I think that the equation is still valid for this situation.
UPDATE: MvdD agree with me:
As the browser does not automatically add the header to your request,
it is not vulnerable to a CSRF attack
I am the author of the Stormpath Blog Post. Storing XSRF token in the JWT isn't about that it is in the JWT, it is about that it is in a cookie. The cookie should be httpOnly, so you can not read it from Javascript.
Now, I think the point that caused a little confusion is where I talk about angular. Angular sets it's only XSRF cookie as well (which is not httpOnly) to put it into the header at request time (which can only be done by javascript on same domain). These are not the same cookie.
If you think about implementing XSRF support in your application, this has been done with storing server side state and the point of storing the XSRF. Storing it in the httpOnly cookie is about being stateless with XSRF. Here, you would validate the JWT signature, get the XSRF out of the claims, and compare it to the header.
The answer to your question is so that you do not need to store state on your server.
My understanding was this:
Store JWT is an HTTPonly cookie.
In that JWT, store a hashed version of an XSRF token.
Send the client the XSRF token when they sign in so they can store it in local storage
Later when the client sends requests, the JWT is automatically sent with each request via cookies and then you also send the XSRF token via a header or query variable and on the server side, re-hash to compare to what's in the JWT on the server
Your JWT is protected from being stolen in a XSS and you're protected from XSRF. XSS could still execute on your browser but could only do damage for that session in the browser. Ultimately, You couldn't stop someone from writing a really detailed script that just ran on your browser, so conventional safeties to protect from XSS are still needed by the web developer.