79

Using React on the frontend with a RESTful API as backend and authorisation by a JSON Web Token (JWT), how do we handle sessions? For example after login, I get a JWT token from REST. If I save it to localStorage I am vulnerable to XSS, if I save it to cookies, same problems except I set cookies to HttpOnly, but React can't read HttpOnly Cookies (I need to read cookie to take JWT from it, and use this JWT with REST requests), also I didn't mention the Cross Site Request Forgery (CSRF) problem. If you're using REST as backend, you can't use CSRF Tokens.

As a result, React with REST seems like a bad solution and I need to rethink my architecture. Is it possible to offer your users a secure React application that handles all business logic on the REST API side without fear of losing their data?

Update:

As far as I understood, it is possible to do this:

  1. React makes an AJAX call to the REST API
  2. React gets a JWT token from the REST API
  3. React writes HttpOnly cookie
  4. Because React can't read HttpOnly cookies, we use it as-is in all our REST calls where we need authentication
  5. The REST API calls to check the XMLHttpRequest header, which is some kind of CSRF protection
  6. The REST API side checks for cookie, reads JWT from it and does stuff

I lack theoretical knowledge here. The logic looks pretty secure, but I still need an answer to my questions and approve of this "workflow".

Henke
  • 4,445
  • 3
  • 31
  • 44
Itsmeromka
  • 3,621
  • 9
  • 46
  • 79
  • 4
    first.. if you are using the JWT token for authentication, why do you even want to read that on front-end. It should be http-only and secured.... second..It is very much possible to use CSRF token with REST. For reference you can check OWASP's guide. Hope this will help https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet – Tasmine Rout Aug 28 '17 at 18:59
  • @TasmineRout but how i can read it on backend? For example i fetch rest api to get JWT, how i can read and save it not on frontend? – Itsmeromka Aug 29 '17 at 20:41
  • Also, as far as i understood of your answer about CSRF, there is a possibility to "secure" your requests and response by just checking XMLHttpRequest header? Also it's said what you can add your own header and check it in requests, but why it's secure? Why possible hacker can't modify his request headers and go through my checks? – Itsmeromka Aug 30 '17 at 15:37
  • 2
    @MyMomSaysIamSpecial you can read about HTTP Only Cookies [here](https://www.owasp.org/index.php/HttpOnly). When you make the rest request to get the token, the server will send it back as a HTTP Only cookie, which the browser stores at its end along with other cookies for your domain. The same cookie is then send along with all the others in every request to your server (ajax or otherwise). You don't have to do anything at the client end for this to happen. In fact it is not allowed by the browser to read the cookies using Javascript. So they cannot be hijacked. – hazardous Aug 31 '17 at 05:17
  • 1
    @MyMomSaysIamSpecial You can read all cookies on back end. You can get it from Http headers. CSRF tokens are to prevent cross site requests. They are used to make sure the requests to the web service is coming from the corresponding UI/user only.They are not used to authenticate or authorise the requester. They are just used to secure the web service from fraudulent requests from outside. They can be session/ request specific, so that no one else can use your token. – Tasmine Rout Sep 01 '17 at 22:33
  • 1
    Have you seen this post? https://stackoverflow.com/questions/27067251/where-to-store-jwt-in-browser-how-to-protect-against-csrf – jannis Sep 06 '17 at 15:11

2 Answers2

34
  1. React makes AJAX call to REST API

assured, lots of restful resource client lib available

  1. React gets JWT token from REST

assured, this is what JWT should do

  1. React writes httponly cookie

I don't think so, It should not work, but session is not such a important thing, it'll soon get out of date, and recheck password on key operations, even the hackers got it in a very short time, you can bind session token together with IP when user login and check it in your backend apis. If you want it most secured, just keep token in memory, and redo login when open new page or page refreshes

  1. Because react can't read httponly cookie, we use it as-is in our all REST call where we need authentication

assured, check user and permissions through login token, like csrf you can put your login token into your request header, and check it in your backend apis. Bind login token to your own restful lib will save you a lot codes

  1. REST on calls checks XMLHttpRequest header, what is some kind of CSRF protection REST side check for cookie, read JWT from it and do stuff

assured, as most people do. Also, bind csrf token to your own restful lib will save you a lot codes

use user token in header https://www.npmjs.com/package/express-jwt-token Authorization JWT < jwt token >

use csrf token in header https://github.com/expressjs/csurf req.headers['csrf-token'] - the CSRF-Token HTTP request header.

restful client https://github.com/cujojs/rest

react with jwt https://github.com/joshgeller/react-redux-jwt-auth-example

Jonnny
  • 4,939
  • 11
  • 63
  • 93
Josh Lin
  • 2,397
  • 11
  • 21
  • can you elaborate on "session is not such a important thing, it'll soon get out of date"? – Stefan Jan 24 '18 at 10:24
  • 4
    how is "you can bind session token together with IP when user login and check it in your backend apis" even a sane idea? IPs are shared all over the place. – Stefan Jan 24 '18 at 10:28
  • 4
    "just keep token in memory, and redo login when open new page or page refreshes" so you suggest to just ignore everything about sessions invented in the last 20+ years and set back web experiences to stone age? – Stefan Jan 24 '18 at 10:29
  • @Stefan `session is not such a important thing` means if you use session or cookie to store login token, then you have to limit it in a short time, or more chance hackers get it and make use of it – Josh Lin Jan 24 '18 at 11:18
  • @Stefan session bind to IP means `session+ip` is valid one IP to many client is OK, this means to keep away the hacker who got user token – Josh Lin Jan 24 '18 at 11:34
  • @Stefan `just keep token in memory` when you want your app most secured, if you store to some place else, there will be more risk hacker will steal it. also `in memory` means better in Closure not `window.loginToken` – Josh Lin Jan 24 '18 at 11:39
  • IP verification does not protect from CSRF. By CSRF definition attacker is leveraging the user’s browser to send the requests. So the requests will carry user's session cookie and IP address. – Andrey Jun 06 '18 at 22:29
  • IP verification does not protect from CSRF, of course not, it is for those who's cookie/sesson got stolen @Andrey – Josh Lin Jun 08 '18 at 04:40
  • Has someone handled this exact problem (CSRF on a secondary cookie) on a Serverless environment? – Jose A Apr 20 '19 at 18:37
  • 1
    @JoseA hope this would help https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md#double-submit-cookie – Josh Lin Apr 22 '19 at 03:39
4

Your server can set the JWT cookie directly as a response to the login request.

The server responds to POST /login with Set-Cookie: JWT=xxxxxx. That cookie is http only and therefore not vulnerable to XSS, and will be automatically included on all fetch requests from the client (as long as you use withCredentials: true).

CSRF is mitigated as you mentioned, see OWASP for details.

  • 3
    "and will be automatically included on all fetch requests" That's why hackers can do CSRF on their victims. – Pieterjan Dec 16 '21 at 13:08
  • just be sure that cookie has Secure and SameSite=strict | lax flag to prevent CSRF https://portswigger.net/web-security/csrf/bypassing-samesite-restrictions#:~:text=SameSite%20works%20by%20enabling%20browsers,action%20on%20the%20vulnerable%20website. – Antolin Bernas May 10 '23 at 21:34