Node Js - Express - CSURF:"invalid csrf token"

Node Js - Express - CSURF : "invalid csrf token"

我正在尝试在 firebase 中托管的 express 应用程序中实施 csurf,但在一种特定情况下我遇到了 'EBADCSRFTOKEN' 错误。 此错误仅在用户通过会话 cookie 登录时发生。

我正在用 JQUERY 发送联系表的数据。 它在没有用户登录时完美运行。

显示联系表的路由

router.get('/contact', async(req, res, next) => { 
  try {
    let user = await RequestHelper.checkSessionCookie(req);
    let data = {
      csrfToken: req.csrfToken()
    };
    if (user) { 
      data.customer = await UserController.getUser(user.uid);
    }
    return res.render('contact', data);
  } catch(error) {
    next(error);
  }
});

Ajax 在联系表中请求

let csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');    
let data = {...}
$.ajax({
  type: "post",
  data: data,
  headers: {
      'csrf-token': csrfToken
  }, 
  url: "/contactForm",
  success: function(code) {
    window.location.href = '/contacted';
  },error:  function (error) {
    console.log(error);
  }
});

处理表单数据的路由

由于您无需登录即可访问此路由,因此我不调用会话中间件。

router.post('/contactForm', async(req, res) => {
  console.log("CSRF OK !");
});

服务器代码

const functions             = require('firebase-functions');
const admin                 = require('firebase-admin');
const path                  = require('path');
const favicon               = require('express-favicon');
const express               = require('express');
const cookieParser          = require('cookie-parser')();
const csurf                 = require('csurf');
const cors                  = require('cors')({origin: true});

admin.initializeApp();

const app                   = express();

app.set('view engine', 'pug');
app.set('views', config.template.directory);

app.use(favicon(path.join(__dirname, '../public', 'favicon.ico')));
app.use(cors);

app.use('/',              require('./routes/webhooks'));

app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(cookieParser);
app.use(csurf({cookie: { httpOnly: true }}));

app.use('/',              require('./routes/routes'));
app.use('/my',            require('./routes/user'));
app.use('/courses',       require('./routes/courses'));

//CSRF ERROR
app.use((error, req, res, next) => {
  if (error.code === 'EBADCSRFTOKEN') {
    console.log(error);
    console.log(req.get("csrf-token")); // <- displays the token perfectly 
    return res.status(403).send();
  } 
  return next(error);
});

创建会话 cookie 的路由

router.post('/sessionLogin', (req, res, next) => {
  const idToken = req.body.idToken;
  const expiresIn = 60 * 60 * 24 * 5 * 1000;
  
  return admin.auth().createSessionCookie(idToken, { expiresIn }).then((sessionCookie) => {
    const options = { maxAge: expiresIn, httpOnly: true, secure: true };
    res.cookie('__session', sessionCookie, options);
    let response = { 
      status: 'success'
    }
    return res.end(JSON.stringify(response));
  },(error) => {
    console.log(error);
    return res.status(401).send();
  });  
});

即使使用我自己的自定义函数来检查令牌,问题也是一样的

app.use(csurf({ cookie: true, value: (req) => {
  console.log(" ------- CHECK CSRF TOKEN ------- ");
  console.log(req.get("csrf-token"));
  return req.get("csrf-token");
}}));

>   ------- CHECK CSRF TOKEN ------- 
>  6wXhahio-AN2f3zlHJPNShNv1KUAB6tOWN3U
>  ForbiddenError: invalid csrf token

感谢您的帮助。

我尝试设置与我用来存储我与 firebase 的会话相同的 cookie 名称,它似乎有效。

app.use(csurf({ cookie: { key: "__session", httpOnly: true }));

来自 firebase 文档:

When using Firebase Hosting together with Cloud Functions or Cloud Run, cookies are generally stripped from incoming requests. This is necessary to allow for efficient CDN cache behavior. Only the specially-named __session cookie is permitted to pass through to the execution of your app.