我一直在try 使用CSRF集成,在遵循了一些指南后,可能IV遗漏了一些东西,但对我来说它看起来还可以(可能仍然IV遗漏了一些东西)

App.js文件:

const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const session = require('express-session');
const MongoDBStore = require('connect-mongodb-session')(session);
const csrf = require('csurf');

require('dotenv').config({path: path.join(__dirname, '/.env')}); //load .env variables

const app = express();
const csrfProtection = csrf();

const tasks = new MongoDBStore({
    uri: process.env.MONGODB_URI,
    session: 'mySessions'
})

app.set('view engine', 'ejs'); //EJS
app.use(express.static(path.join(__dirname, '..', '..', 'public'))); //static folder route
app.use(session({
    secret: 'my secret',
    resave: false,
    saveUninitialized: false,
    tasks : tasks
})) // setting up a session
app.use(csrfProtection); //csrf middleware


app.use((req, res, next) => {
    res.locals.isAuth = req.session.isLoggedin; //True after logging in
    res.locals.csrfToken = req.csrfToken();
    next();
})

// Routes
const userData = require('../routes/user.js');
const listRoute = require('../routes/list.js');
const adminData = require('../routes/admin.js');
const errorController = require('../../controllers/errorController');

//Middleares
app.use(bodyParser.urlencoded({ extended: false })) //Body-Parser
app.use(express.static(path.join(__dirname, "node_modules/bootstrap/dist/"))); //bootstrap
app.use(userData);
app.use(listRoute);
app.use(adminData);
app.use(errorController.error404); //404 page


// Wait for database to connect, logging an error if there is a problem
mongoose.connect(process.env.MONGODB_URI)
      .then(() => {
        console.log('Mongoose connect: Connected');
        app.listen(process.env.PORT);
        console.log('Listening to port 3000')
      })
      .catch();

当我try 登录时,IM重定向并收到消息"禁止错误:无效的CSRF令牌"

以下是用户交互文件UserController.js:

const User = require('../models/user');
const bcrypt = require('bcryptjs');
const path = require("path");
const PASSWORD_SECURITY_LEVEL = 10;

exports.getRegisterUser = (req, res, next) => {
    console.log('inside registerUser in userContorller');
    res.render('../views/register', {
        pageTitle: 'Register'
    });
}

exports.getLoginUser = (req, res, next) => {
    res.render('../views/login', {
        pageTitle: 'Login',
    })
};

//TODO:Check what went wrong when logging it just redirecting maybe something with the form action check!!!
exports.postLoginUser = (req, res, next) => {
    const username = req.body.username;
    const password = req.body.password;

    //check csrfToken valid TODO:not sure this is wokrking maybe try something else
    if(req.csrfToken() !== req.body._csrf){
        res.status(403).send('CSRF token validation failed');
        return;
    }

    User.findOne({username: username})
        .then((user) => {
            if(!user){
                //TODO: Show proper message
                console.log('User field is empty');
                res.redirect('/login');//User not found
            }
            //check if the password is correct
            bcrypt.compare(password, user.password)
                .then(passwordMatch => {
                    if(passwordMatch){
                        req.session.isLoggedin = true; //setup a session
                        req.session.user = user //save the user found in foundOne at the first .then
                        console.log('Password matched saving session and redirecting...')
                        return req.session.save((err) => {
                            if(err){
                                console.log('req.session.save error: ',err);
                            }else{
                                res.redirect('/');
                            }
                        })
                    }else{
                        //TODO: Show proper message.
                        console.log('Password is not correct redirecting back to login page.')
                        res.redirect('/login');
                    }
                })
        }).catch(err => {
            console.log('findOne error is: ', err);
    })
}

exports.postUserRegister = (req, res) => {
    const username = req.body.user;
    const password = req.body.password;

    User.findOne({username: username})
        .then((userFound) => {
            if (userFound) { //new user tried to register with the same username WAS found.
                console.log('Username is already exists!');
                res.redirect('/register');
            } else{
                return bcrypt.hash(password, PASSWORD_SECURITY_LEVEL)
                    .then(hashedPassword => {
                    const newUser = new User({
                        username: username,
                        password: hashedPassword
                    });
                    newUser.save()
                        .then(() => {
                            console.log('New user saved succesfuly')
                            res.redirect('/login');
                        })
                        .catch((err) => {
                            console.log('postUserRegister err:', err);
                            res.redirect('/register')
                        })
                });
            }
        })

        .catch(err => console.log('postUserRegister error: ', err)); //ADDED NEW LINE MIGHT CAUSE PROBLEM IN REGISTER PAGE
}

exports.postUserLogOut = (req, res) => {
    req.session.destroy((err) => {
        console.log(err)
        res.redirect('/login');
    });
}

和login.ejs文件:

<!DOCTYPE html>
<html lang="en">

<head>
    <!-- Required meta tags-->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="Colorlib Templates">
    <meta name="author" content="Colorlib">
    <meta name="keywords" content="Colorlib Templates">

    <!-- Title Page-->
    <title><%= pageTitle %></title>

    <!-- Icons font CSS-->
    <link href="/vendor/mdi-font/css/material-design-iconic-font.min.css" rel="stylesheet" media="all">
    <link href="/vendor/font-awesome-4.7/css/font-awesome.min.css" rel="stylesheet" media="all">
    <!-- Font special for pages-->
    <link href="https://fonts.googleapis.com/css?family=Poppins:100,100i,200,200i,300,300i,400,400i,500,500i,600,600i,700,700i,800,800i,900,900i" rel="stylesheet">

    <!-- Vendor CSS-->
    <link href="/vendor/select2/select2.min.css" rel="stylesheet" media="all">
    <link href="/vendor/datepicker/daterangepicker.css" rel="stylesheet" media="all">

    <!-- Register CSS-->
    <link href="/css/register.css" rel="stylesheet" media="all">
</head>

<body>
<div class="page-wrapper bg-gra-02 p-t-130 p-b-100 font-poppins">
    <div class="wrapper wrapper--w680">
        <div class="card card-4">
            <div class="card-body">
                <h2 class="title">Log in</h2>
                <form action="/login-user" method="post">
                    <!--Username -->
                    <div class="row row-space">
                        <div class="col-2">
                            <div class="input-group">
                                <label class="label">Username</label>
                                <input class="input--style-4" type="text" name="username">
                            </div>
                        </div>
                    </div>
                    <!--Password -->
                    <div class="row row-space">
                        <div class="col-2">
                            <div class="input-group">
                                <label class="label">Password</label>
                                <input class="input--style-4" type="password" name="password">
                            </div>
                        </div>
                    </div>
                    <!-- Login button press-->
                    <form action="/login-user" method="post">
                        <div class="p-t-15">
                            <div>
                                <input type="hidden" name="_csrf" value="<%= csrfToken %>">
                                <button class="login-btn btn--radius-2 btn--blue" type="submit">Log in</button>
                            </div>
                        </div>
                    </form>
                </form>

                <!--Register Button redirect -->
                <div class="p-t-15">
                    <label class="not-registered-label">Don't have a user?</label>
                    <div>
                        <a class="login-btn btn--radius-2 btn--blue" href="./register">Register Now!</a>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

</body>

</html>
<!-- end document-->

感谢您的帮助,如有任何帮助,将向您表示感谢(:

推荐答案

很可能您的<input type="hidden" name="_csrf" value="<%= csrfToken %>">包含空值,因为从我所看到的情况来看,您从未将csrfToken与您的观点一起发送.try 将其作为可选的第二个参数对象的属性添加到res.render方法中,用于您知道将需要它的所有视图,例如,对于表单提交,如下所示:

res.render('../views/register', {
   pageTitle: 'Register',
   csrfToken: req.csrfToken() //< Add this
});

//..

res.render('../views/login', {
   pageTitle: 'Login',
   csrfToken: req.csrfToken() //< Add this
})

你似乎也有<form><form>之间,这可能会给你带来一些问题.此表单包含在外部表单中.嵌套表单不符合HTML规范:

<form action="/login-user" method="post">
   <div class="p-t-15">
      <div>
         <input type="hidden" name="_csrf" value="<%= csrfToken %>">
         <button class="login-btn btn--radius-2 btn--blue" type="submit">Log in</button>
      </div>
   </div>
</form>

Node.js相关问答推荐

如何使用updateMany()和Node.js的方法?

Mongoose:如何在文档中推送到Caped(有限大小,滚动窗口)数组?

Axios TypeError:将循环 struct 转换为 JSON

当try 将 formData 转换为 express js 时,服务器无法识别 multipart/form-data

无法使用 node 预签名 url 从 React 将图像文件上传到 s3

ResponseError:键空间ks1不存在

在系统启动时启动本地 node 服务器

NodeJS 中的流 API 数据如何流动?

后端位于 Docker 容器中时的 SvelteKit SSR fetch()

如何在拦截器中发送不同的请求?

如何在 MongoDB collection.find() 上获取回调

构建 vue cli 后如何运行生产站点

在 Node.js 中的两个不同进程之间进行通信

判断一个数组中的每个元素是否都在第二个数组中

npm publish 导致'错误:EPERM:不允许操作,取消链接...',errno -4048

如何在 Joi 字符串验证中使用枚举值

如何从 npm 注册表中删除 npm 包?

Express.js中的bodyParser.urlencoded({extended: true }))和bodyParser.json()是什么意思?

如何从 find 方法返回 Mongoose 结果?

使用 Node-sass 缩小 CSS