0

I have a website that runs on example.com. The website makes AJAX calls to my backend API which sits at api.example.com.

I employ a double-submit verification strategy.

The backend has protected endpoints which check the JWT token with each request. The JWT token is stored in a httpOnly cookie. It also contains the CSRF token.

Alongside the JWT cookie I also send a CSRF cookie which is not httpOnly. Each request that the client makes must contain the value of this cookie in a special header.

So far so good, but, I want to make sure that the client does everything in its power to prevent users from making pointless unauthenticated requests. So in my React app I have declared a few private routes which check if the user is logged in and if they are not, the user is redirected to the login page.

The way I check if a user is authenticated is by checking if they have the CSRF cookie. If they do, they are allowed to navigate to the protected page. All subsequent requests on this page are still verified on the backend for a JWT and CSRF token.

My question is, is this a valid way to check that the client is authenticated on the client-side?

Additionally, should I be setting the sameSite cookie option to True for both cookies?


EDIT

One thing I have just thought of is that it is probably better to create a simple endpoint on the backend that is used to check if the user is logged in. So instead of just checking the cookie, the client can submit a request to this endpoint and verify that the token in the cookie is still valid.

turnip
  • 785
  • 1
  • 6
  • 9
  • Since you only check the CSRF cookie is there, it seems to mean that a visitor who manually create such cookie (with dumb value) will be considered as "logged in". If a valid value is required, I'll just login once, get the value, log out and I now have a forever-valid CSRF cookie to mimic being logged in. – Xenos May 06 '20 at 15:53

3 Answers3

1

I want to make sure that the client does everything in its power to prevent users from making pointless unauthenticated requests.

... Why though? You can't prevent it, at all; the client is 100% under the user's control. If somebody wants to make "pointless unauthenticated requests", they're going to do it and there is zilch you can do about it. Why do you care though? Authentication is 100% the server's responsibility. Just return an error and/or redirect (depending on whether it's a page request or API request).

is this a valid way to check that the client is authenticated on the client-side?

Invalid category; no such thing exists. The client doesn't know, can't know, if the server considers it authenticated or not, except by making a request and checking the response. This is like asking "is <literally anything> a valid way to check if this lottery ticket is the winning number without looking at anything but the ticket?" No

To be clear, it's not insecure to attempt this. If your client makes any security decisions about the result of this check, that is a security bug, but the root cause is "client makes any security decisions", full stop. Don't do that. If this is just, like, a user-friendly behavior... well, how to best implement that doesn't belong on this site, but that entire class of thing is not insecure.


Slightly off-topic, but:

Each request that the client makes must contain the value of this cookie in a special header.

Double-submit cookies are a relatively weak CSRF prevention strategy. Better than nothing but not good. They're also completely redundant with the step of "require a special header", assuming you haven't done something completely insecure with your CORS policy. Any third-party site that tries to send a custom header at all will trigger a CORS pre-flight; if your site doesn't allow it (as well it shouldn't, or you may have a separate vulnerability there) then the browser won't send the actual request (containing the cookies, including the access token) at all.

CBHacking
  • 40,303
  • 3
  • 74
  • 98
0

This is more a web application architecture question than a security one.

Isn't having a JWT token enough to consider the user logged from the client side perspective?

I assume the user authenticate before getting the token, presumably from the successful login response.

When the token expired return an unauthorized response, look for this response on every ajax response (https://github.com/axios/axios#interceptors) and redirect the user to the login page.

Ron
  • 1
  • > Isn't having a JWT token enough to consider the user logged from the client side perspective? -- depends what you mean. The client-side JS cannot read the token value. It cannot even see the cookie. Regardless, I after thinking about this more I think it is more of a React specific questions... since my issue is about persisting the logged in state. – turnip Jul 11 '19 at 13:59
0

Instead of checking if user is eligible to perform a request to some resource (API) I would implement security check on resource side (as possibly you already have). In this case the API is validating all the cookies and if not resource is reacting on not secure request.

This solution architecture is easier to be implemented and to understand. The only check on client side to see if user is authenticated can be useful if you want to somehow adjust UI on this state but for this I would use some different cookie than CSRF cookie.

SameSite cookie setting to "true" is not possible. you can only set "None", "Stric" or "Lax". The setting depends on this, if the cookie will be used on "cross site" use cases.

Bartosz Rosa
  • 337
  • 1
  • 6