Psifi-Solutions / csrf-csrf

A utility package to help implement stateless CSRF protection using the Double Submit Cookie Pattern in express.
Other
113 stars 17 forks source link

Invalid CSRF error after making ajax get call #36

Closed doaortu closed 10 months ago

doaortu commented 11 months ago

Hi @psibean , thanks for making this library.

I met an issue when I use this library. Somehow I got invalid csrf error after I'm making ajax GET call. One thing I notice, after I make the ajax GET call, I got Set-Cookie Response Header which changed the x-csrf-token cookie in the browser. I guess that's why I got the invalid csrf error on the subsequent request.

I don't know if that's by design or not, do you have any idea how to solve this issue?

Thanks in advance.

davidgonmar commented 11 months ago

Hey! Can you send more information about the issue? I think the code where you are using the library, the route handler that is throwing the error and the code that is calling that route would help:)

psibean commented 11 months ago

Hey @doaortu as mentioned ^ it could help if you provide some details on what you've implemented and when / where you are choosing to generate a token.

One thing I notice, after I make the ajax GET call, I got Set-Cookie Response Header which changed the x-csrf-token cookie in the browser.

You choose to generate a token yourself by calling either req.csrfToken() or generateToken(req, res). It's entirely up to you when to generate a token. If you're generating a token when you don't want to, then simply don't do that. You are in 100% control of when a token is generated.

If you are calling these methods when making the specific GET request, then this means you are generating the token as part of that requests middleware processing. This is entirely in your control. You should structure your middleware and routes and such so that you're only generating the token when you want/need to, and whenever a token is generated, make sure you're providing it to the frontend so that you can put it in the header (or wherever you're hoping to put it based on your getTokenFromRequest if customised).

I don't know if that's by design or not,

There is no token generation by design. csrf-csrf itself will never generate a token for you, a token is only generated when YOU make the calls as mentioned in the previous paragraph.

What is strange though, is it should return the same token if one already exists, unless you're passing in true for the overwrite parameter

doaortu commented 11 months ago

Ahh so that's why.

Thanks @davidgonmar and @psibean for the quick reply and for the awesome explanation.

Yes, I do call req.csrfToken() in my middleware. So in my case, I make a middleware to provide common data for all of my views, including the csrfToken. Sometimes I also need to return the rendered views from ajax, so I apply the middleware to the ajax routes too.

I guess I need to restructure it somehow, maybe I'll add req.xhr check before calling the req.csrfToken() to detect if it's an ajax call or not.

Anyway. Thanks again for the great support.

psibean commented 11 months ago

Ahh so that's why.

Thanks @davidgonmar and @psibean for the quick reply and for the awesome explanation.

Yes, I do call req.csrfToken() in my middleware. So in my case, I make a middleware to provide common data for all of my views, including the csrfToken. Sometimes I also need to return the rendered views from ajax, so I apply the middleware to the ajax routes too.

I guess I need to restructure it somehow, maybe I'll add req.xhr check before calling the req.csrfToken() to detect if it's an ajax call or not.

Anyway. Thanks again for the great support.

It's still interesting, because even if you call req.csrfToken() multiple times, it should be returning the same token unless you explicitly pass overwrite as true like this: req.csrfToken(true). So even if you're calling it, if you aren't overwriting the existing token, it should still work.

And this hints that there may be something else wrong.

davidgonmar commented 11 months ago

Ahh so that's why. Thanks @davidgonmar and @psibean for the quick reply and for the awesome explanation. Yes, I do call req.csrfToken() in my middleware. So in my case, I make a middleware to provide common data for all of my views, including the csrfToken. Sometimes I also need to return the rendered views from ajax, so I apply the middleware to the ajax routes too. I guess I need to restructure it somehow, maybe I'll add req.xhr check before calling the req.csrfToken() to detect if it's an ajax call or not. Anyway. Thanks again for the great support.

It's still interesting, because even if you call req.csrfToken() multiple times, it should be returning the same token unless you explicitly pass overwrite as true like this: req.csrfToken(true). So even if you're calling it, if you aren't overwriting the existing token, it should still work.

And this hints that there may be something else wrong.

Yeah. @doaortu can you send some code where the issue is reproducible? A repo would be ideal:)

psibean commented 10 months ago

Hey @doaortu will assume you've sorted this one out since we haven't heard from you in a while.

Feel free to comment here and re-open the issue if you're still having problems.