1

So the csurf middleware used in Node.js applications has been deprecated since Sept 2022 due to security vulnerabilities being discovered by Fortbridge in Aug 2022. However, it it still being downloaded almost as much now as it was 1 year ago before the vulnerabilities were published. For example, 11-Jun-22 - 17-Jun-22 = 370,190 downloads per week. 03-Jun-23 - 09-Jun-23 = 337,097 downloads per week. This tells me it's relatively just as popular now as it was last year.

According to veracode. All versions of csurf library are vulnerable if:

  1. csurf is setup to use double-submit cookies – csurf({cookie: true})
  2. default value function is in use

The authors of csurf are advising to use an alternative.

The OWASP Cheat Sheet advises that:

  • Check if your framework has built-in CSRF protection and use it (Express doesn't)
  • For stateful software use the synchronizer token pattern
  • For stateless software use double submit cookies

So far I have tried csrf-sync as it uses the Synchroniser Token Pattern but has only 2k weekly downloads. I have also looked into csrf-csrf package as it uses the Double Submit Cookie Pattern but again, it only has 38k weekly downloads.

My question therefore is which secure alternative middleware(s) is going to provide me with the best protection from Cross-Site Request Forgery attacks in Node with Express? There doesn't seem to be a clear option and I'd like to protect my organisation.

1 Answer 1

1

I don't use Express personally, but the simplest option is really quite basic: do not use cookies for authentication/session management. If your tokens are sent in some way that needs to be manually configured, such as a Bearer token, then CSRF is impossible; the attacker don't know the token value and as such can't send authenticated requests. You lose the mitigation of it being impossible for XSS to steal the token out of an HttpOnly cookie - though there's ways to mitigate that with a hybrid cookie + non-cookie system - but honestly that mitigation isn't worth very much anyhow.

Alternatively, do you need your client to do anything that uses, or could be imitated by, submitting an HTML form? If not, there's another strong mitigation to CSRF: make all the state-changing requests use script-initiated requests that are not simple (they could not be made by an HTML form submission), in which case the browser won't send such requests cross-origin without a CORS preflight receiving approval first. Then, as long as you don't configure CORS to allow untrusted sites to make those requests, you're fine.

This is similar work to the first solution (since that also requires every authenticated request be script-initiated), but unlike the first solution it doesn't require changing how session tokens are handled. Instead, you just implement some requirement like that there's a custom header called something like X-No-CSRF on every state-changing request - it doesn't even need a unique value, just ensure it exists at all - and make the client send that. If the frontend and backend are at different origins (e.g. app.example.com and api.example.com) you'll need to configure CORS on the backend to allow the frontend domain - and nothing else! - to make authenticated requests and set the relevant header (or whatever other way you choose to force a CORS preflight). Make sure not to trust any origins other than the legitimate frontend origin[s].

6
  • I appreciate the advice but the applications I support are all CRUD applications where updates/inserts to the data models are done using HTML post requests. They also already have express-session implemented for handling state with sessions persisted to the database. CORS is configured to not allow cross origin. If a secure, sameSite, httpOnly cookie is used for session but cookie:false option is used for csurf and the _csrf hidden input value is sent either directly in the form or using fetch in the headers parameter then is that sufficient?
    – jQueeny
    Commented Jul 11, 2023 at 21:29
  • Please don't use JWT(the most popular of Bearer tokens) as sessions, they are not suitable substitute, in fact many security practitioners have started advocating against their use in any capacity. I would recommend taking the OWASP advice lightly, use an alternative package, but rely on a code review for security rather than its popularity metrics (downloads/week). If you do choose to use tokens for authentication, do some research and choose the right one for your architecture, not the popular one (JWT)
    – wireghoul
    Commented Jul 12, 2023 at 0:30
  • @jQueeny That's probably sufficient, but I haven't personally reviewed the csurf library and can't vouch for its correctness (and even if I could, this site is not for software recommendations; they go out of date too fast). Since it's not using cookies it is presumably (hopefully) generating a unique token and tying it to the user session, either via server-side session state or by using a cryptographic hash of the token. Securely preventing CSRF isn't technically difficult at all; it's making sure that every state-changing action is covered and performance is acceptable that gets hard.
    – CBHacking
    Commented Jul 12, 2023 at 8:08
  • @wireghol I don't mix sessions with JWT and have always relied on built-in framework (Laravel) session handling and csrf so have no real experience with JWT. However I now support some apps built (quite well) with Express and code review picked up vulnerability with csurf package no need to ensure safe use.
    – jQueeny
    Commented Jul 12, 2023 at 8:36
  • @CBHacking yes, a csurf secret is stored in session persisted to db. When user submits form or fetch request the csurf key is added and session id take from cookie used on server to find session in db to compare csurf key against csurf secret. So not using csurf key in cookie seems secure?
    – jQueeny
    Commented Jul 12, 2023 at 8:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .