Search code examples
node.jsexpressnginxexpress-session

expressjs, nginx proxy, csurf and secure cookies not working


I've got an Express site running behind a proxy with nginx, everything was working fine on my local development machine with regards to csrf protection using csurf and insecure cookies.

I've since moved to a staging site which has an SSL cert. Now I'm using SSL I want to enable secure cookies. However csurf now always errors with an invalid csrf token whenever I submit a form.

I setup my express-session like so:

app.set('trust proxy', 1)
app.use(session({secret:'secret' , resave:false,proxy:true, saveUninitialized:false, store:sessionStore, rolling:true, cookie:{secure:true}}))
//...other setup lines
let csrf = csurf()
app.use(csrf)

and my nginx set-up is as follows:

        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header x-forwarded-proto https;
        proxy_cache_bypass $http_upgrade;

As far as I can tell from the docs this should all be fine. My webapp is running from GCP, but I don't think that should make any difference.

I've tried clearing my cookies etc. on my machine in case something was cached somewhere but it still won't work. Moving back to secure:false fixes the issue.

I have a catch all app.post route handler to validate a csrf token as there are multiple forms on the page and the new csrf token is created after this route has fired and as I mentioned earlier this all worked fine without secure cookies as well. I've also tried passing my session secret to the cookieParser() as well but to no avail and the solutions at Express-session Secure Cookies not working also don't work (such as setting resave:true). There's no AJAX requests going on either it's a straight POST and the token is rendered correctly in the form.

Is there something obvious I'm missing here?


Solution

  • I just did something similar, and at least on my setup I had to specify the following array in my trust proxy in express.

    app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']);
    

    I also believe express wants to see all of the standard x-forwarded headers, not just -proto. Here's the config I used for them:

    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;