【问题标题】:I get "ForbiddenError: invalid csrf token" when I try to use {cookie: { secure: true }} session configuration. How do I implement this?当我尝试使用 {cookie: { secure: true }} 会话配置时,我得到“ForbiddenError: invalid csrf token”。我该如何实施?
【发布时间】:2021-03-26 07:32:45
【问题描述】:

我不明白为什么这不起作用。当我单击登录时,我收到此“ForbiddenError:无效 csrf 令牌”消息,但我读到必须在会话中启用 {cookie: {httpOnly: true, secure: true}} 选项才能运行相对安全的应用程序(我使用 JWT,并且是会话和 cookie)

这是我的文件:

app.js

 // ____ Imports ____
    const path = require('path');
    const express = require('express');
    const bodyParser = require('body-parser');
    const sessionConfig = require('./middleware/sessions');
    const userProvider = require('./middleware/userProvider');
    const connectDB = require('./services/db');
    const csrf = require('csurf');
     
    // ____ Middlewares ____
    const app = express();
    const csrfProtection = csrf();
    app.set('view engine', 'ejs');
    app.set('views', 'views');
    app.use(bodyParser.urlencoded({ extended: false }));
    app.use(express.static(path.join(__dirname, 'public')));
    app.use(sessionConfig);
    app.use(userProvider);
    app.use(csrfProtection);
    app.use((req, res, next) => {
      res.locals.isAuth = req.session.isAuth;
      res.locals.csrfToken = req.csrfToken();
      next();
    });
     
    // ____ Routes ____
    const adminRoutes = require('./routes/admin');
    const shopRoutes = require('./routes/shop');
    const authRoutes = require('./routes/auth');
    const errorController = require('./controllers/error');
    app.use('/admin', adminRoutes);
    app.use(shopRoutes);
    app.use(authRoutes);
    app.use(errorController.get404);
     
    // ____ Database & Server spin-up ____
    const PORT = process.env.PORT || 3000; //deployment looks for process.env.PORT
    connectDB(() => {
      app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
    });

./middleware/sessions.js

const session = require('express-session');
const MongoDBStore = require('connect-mongodb-session')(session);
const config = require('config');
 
const store = new MongoDBStore({
  uri: config.get('mongoURI'),
  collection: 'sessions',
});
 
const sessionConfig = session({
  secret: config.get('sessionSecret'),
  resave: false,
  saveUninitialized: false,
  store: store,
  cookie: { httpOnly: true, secure: true },
});
 
module.exports = sessionConfig;

./middleware/isAuth.js

module.exports = (req, res, next) => {
  if (!req.session.isAuth) {
    return res.redirect('/login');
  }
  next();
};

./middleware/userProvider.js

 const User = require('../models/user');
     
    module.exports = async (req, res, next) => {
      try {
        if (!req.session.user) {
          return next();
        }
        let user = await User.findById(req.session.user._id);
        req.user = user;
        next();
      } catch (error) {
        console.log(error);
      }
    };

postLogin 控制器(通过 isAuth 中间件)

    exports.postLogin = async (req, res) => {
  try {
    let { email, password } = req.body;
    let user = await User.findOne({ email: email });
    let doMatch = await bcrypt.compare(password, user.password);
    if (doMatch) {
      console.log('Match!');
      //use .save() method to make sure it redirects only when session is already created
      req.session.user = user;
      req.session.isAuth = true;
      return req.session.save(() => {
        res.redirect('/');
      });
    } else {
      return res.redirect('/login');
    }
  } catch (error) {
    console.log(error);
  }
};

./views/auth/login.ejs

<%- include('../includes/head.ejs') %>
    <link rel="stylesheet" href="/css/forms.css">
    <link rel="stylesheet" href="/css/auth.css">
</head>

<body>
   <%- include('../includes/navigation.ejs') %>

    <main>
        <form class="login-form" action="/login" method="POST">
            <div class="form-control">
                <label for="email">E-Mail</label>
                <input type="email" name="email" id="email">
            </div>
            <div class="form-control">
                <label for="password">Password</label>
                <input type="password" name="password" id="password">
            </div>
            <input type="hidden" name="_csrf" value="<%= csrfToken %>">
            <button class="btn" type="submit">Login</button>
        </form>
    </main>
<%- include('../includes/end.ejs') %>

确实在 mongoDB 中创建了会话,但没有定义用户或 isAuth(在下面的文档中显示为 isLoggedin)。

【问题讨论】:

    标签: mongodb session cookies csrf csrf-token


    【解决方案1】:

    缩小到secure: true 问题后(当我第一次问我不知道是什么导致了这种行为时),我发现这个线程解释了http 服务器没有得到secure: true cookie (express-session secure: true)

    在 localhost 我使用 http 所以这当然行不通。当我把它放在生产环境中时它起作用了:)

    【讨论】:

      猜你喜欢
      • 2021-04-28
      • 2017-05-21
      • 2023-03-22
      • 2016-05-05
      • 2018-05-10
      • 2011-04-10
      • 2022-09-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多