我在设置 csrf 时遇到问题。我希望有人能指出我正确的方向。
我将 next.js 与 express.js 一起使用。
当我刷新页面时会发生以下情况:
我真的被这个错误弄糊涂了,真的不明白出了什么问题。这是一些相关的代码:
server.js:
require("dotenv").config();
const express = require("express");
const next = require("next");
const bodyParser = require("body-parser");
const cors = require("cors");
const cookieParser = require("cookie-parser");
const routes = require('./routes');
const csrf = require("csurf");
const csrfProtection = csrf({
cookie: true,
});
//next.js configuration
const dev = process.env.NODE_DEV !== "production";
const nextApp = next({ dev });
const port = 3000;
const handle = nextApp.getRequestHandler();
nextApp.prepare().then(() => {
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cors());
app.use(cookieParser());
app.use((err, req, res, next) => {
res.status(500).send("Something went wrong!");
});
app.use(csrfProtection);
app.use('/api', routes);
app.get("*", (req, res) => {
return handle(req, res);
});
//start server
app.listen(port, (err) => {
if (err) throw err;
console.log(`listening on port ${port}`);
});
});
路由/index.js:
const express = require('express')
const router = express.Router()
const getCsrfToken = require('../controllers/csrf')
const postSignupQ = require("../controllers/postSignupQ");
const attachUser = require("../middleware/attachUser");
router.get("/csrfToken", getCsrfToken.getCsrfToken);
router.use(attachUser);
router.post("/signupQ", postSignupQ.postSignupQ);
module.exports = router
控制器/csrf.js
const getCsrfToken = (req, res) => {
res.json({ csrfToken: req.csrfToken() });
};
module.exports = { getCsrfToken };
context - 这里我是 console.log(csrf):
useEffect(() => {
const getCsrfToken = async() => {
const { data } = await axios.get('api/csrfToken');
console.log("csurf", data);
axios.defaults.headers['X-CSRF-Token'] = data.csrfToken;
};
getCsrfToken();
}, []);
我不明白为什么会收到错误消息,当我第一次发出 POST 请求以及刷新页面时,一切正常。有什么问题,我该如何解决?
编辑
感谢 Jack Yu,上面的代码片段正在运行。也许它可以帮助其他人..
答案 0 :(得分:0)
我还发现您的 api 路径可能是错误的。在您的 axios 中是 await axios.get('csrfToken')
。但是,我在您的路由器中看到了 /api/csrfToken
。将其更改为 await axios.get('/api/csrfToken')
在 csurf 包中,当您在中间件中多次使用带有 cookie 模式的 csurf({cookie: true})
时,它会在第一次发布的响应头中破坏 csrf 令牌。您可以在 CSRF doesn't work on the first post attempt 中查看更多详细信息,我已在该帖子中解释了原因。因此,您可以使用两种解决方案。
根据评论,您在 app.use(csruf({cookie: true}))
和 server.js
中使用了 router/index.js
。删除 router/index.js
中的以下行。当您在 server.js
中设置 csruf 时,您可以在 req.csrfToken()
中使用 controllers/csrf.js
,而无需再次设置 csruf。
const csrf = require("csurf");
const csrfProtection = csrf({
cookie: true,
});
router.use(csrfProtection);
您需要使用 express-session
包。在 csurf
之前添加以下代码。如果您的 .use(csrf({cookie: true}))
中有 routes/index.js
,请将其删除。
const session = require('express-session')
// mark1: change it to false
const csrfProtection = csrf({
cookie: false,
});
// blablabla ... other code
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cors());
app.use(cookieParser());
// mark2: put here
app.use(session({
name: "test",
secret: "test",
cookie: { maxAge: 3 * 60 * 60 * 1000 },
resave: false,
saveUninitialized: false
}))
// put here
app.use((err, req, res, next) => {
res.status(500).send("Something went wrong!");
});
app.use(csrfProtection);
app.use('/api', routes);
然后在所有 csurf 设置中将 {cookie: true}
更改为 {cookie: false}
。当您使用会话模式时,您可以在中间件中多次使用 csruf({cookie: false})
。
答案 1 :(得分:0)
我们需要在 header 中传递一个 cookie,如下所示:
headerMaps.put("cookie", "_csrf=value; connect.sid=value; csrfToken=value")