Node js csrf令牌保护不起作用
Posted
技术标签:
【中文标题】Node js csrf令牌保护不起作用【英文标题】:Node js csrf token protection not working 【发布时间】:2019-05-11 07:54:04 【问题描述】:在bodyParser
之后,我的app.js
文件服务器端有以下内容
let dotEnv = require("dotenv");
dotEnv.load();
let express = require("express");
let app = express();
if (process.env.NODE_ENV === 'production')
app = require('./public/web/server').app;
let passport = require("passport");
let server = require("http").Server(app);
let io = require("socket.io").listen(server);
// load intial configuration
require("./startup/initial-configuration")(app, io);
require("./server/config/socket")(io);
require("./server/config/database")(app, process.env.NODE_ENV);
require("./server/authentication/passport.local")(passport);
require("./server/authentication/passport.impersonate");
require("./startup/initial-routes")(app);
if (process.env.NODE_ENV === 'production')
app.get('*.*', express.static('./public/web/browser',
maxAge: '1y'
));
app.get('*', (req, res) =>
res.render('index',
req,
res
, (err, html) =>
if (html)
res.send(html);
else
// console.error(err);
res.send(err);
);
);
require("./server/middleware/custom-middleware")(app);
module.exports = app: app, server: server ;
如您所见,我在app.js
中加载了一个文件initial-configuration
,该文件的内容是:
const path = require("path");
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
const csurf = require("csurf");
const helmet = require("helmet");
const compression = require("compression");
const useragent = require("express-useragent");
const cors = require("cors");
const passport = require("passport");
const express = require("express");
const cookieMiddleware = require("../server/middleware/cookie-middleware");
const checkCSRFMiddleware = require("../server/middleware/checkCSRF-middleware");
const notificationModel = require("../server/model/notification/notification.model");
const logger = require("./logger");
const morgan = require("morgan");
module.exports = (app, io) =>
app.set("case sensetive routing", true);
if (process.env.NODE_ENV === "production")
app.enable("trust proxy");
app.use((req, res, next) =>
res.io = io;
res.header(
"Access-Control-Allow-Headers",
"X-CSRF-Token, Content-Type"
);
notificationModel.setIO(io);
next();
);
let corsOption =
origin: true,
methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
credentials: true,
exposedHeaders: ["x-auth-token"]
;
app.use(cors(corsOption));
// app.use(logger('dev'));
app.use(helmet());
app.use(useragent.express());
app.use(compression());
app.use(bodyParser.json());
app.use(
bodyParser.urlencoded(
extended: false
)
);
app.use(cookieParser());
app.use(cookieMiddleware);
app.use(passport.initialize());
app.use(require('csurf')(cookie: true))
// error handler
app.use(function (err, req, res, next)
if (err.code !== 'EBADCSRFTOKEN') return next(err)
// handle CSRF token errors here
res.status(403)
res.send('session has expired or form tampered with')
)
app.use(function (req, res, next)
res.cookie('XSRF-TOKEN', req.csrfToken())
next()
)
// app.use(express.static(path.join(__dirname, "../public/web/browser")));
app.use(
morgan("combined",
stream: logger.stream
)
);
;
在 Angular 中,我只在 app.module 中导入了以下几行
HttpClientXsrfModule.withOptions(
cookieName: "XSRF-TOKEN",
headerName: "X-CSRF-TOKEN"
),
我所有的请求头都有
Cookie:_csrf=TmghRq3eWC-PxQfp6pvuHw07; XSRF-TOKEN=vMPrZZtA--BgtY1YVqDRXmi5A6RSbMNb61JA
但是我所有的帖子请求都失败了,并说code: "EBADCSRFTOKEN"
。
我应该在角度方面做点什么吗?我应该将其附加到表单数据中吗?
任何帮助谢谢。
这是我的请求详情
【问题讨论】:
你能分享你发布数据的角度代码吗?我认为您的 CSRF 令牌包含不正确-您还提到您的请求标头具有 Cookie-您确定它不是响应标头吗? @MaviDomates 我没有对我的 Angular 发布请求做任何事情,不知道我该怎么办 【参考方案1】:在您的代码中,您使用了许多模块。为了隔离问题,我建议将您的代码减少到最小版本,删除所有非强制启用 csrf 的内容。
这只是一个建议,但是在我的 Angular 7 应用程序中我添加了这个(不需要更改 cookiename 和令牌,因为它们在 Angular 的源代码中具有默认值):
HttpClientModule,
HttpClientXsrfModule.withOptions()
然后在我的服务器(主文件 app.js)中使用 Express 4 我添加了这段代码(按这个确切的顺序):
const csrf = require('csurf');
app.use(bodyParser.urlencoded(
extended: false
));
// then add cookie parser and csrf config
app.use(cookieParser());
app.use(csrf(
cookie:
// here you can configure your cookie. Default values are ok, but I decided to be more explicit
// http://expressjs.com/en/4x/api.html#req.cookies
key: '_csrf',
path: '/',
httpOnly: false, // if you want you can use true here
secure: false, // if you are using HTTPS I suggest true here
signed: false, // I don't know if csurf supports signed cookies, so I used false
// not mandatory, but if you want you can use sameSite: 'strict'
// sameSite: 'strict', // https://www.owaspsafar.org/index.php/SameSite
maxAge: 24 * 60 * 60 * 1000 // 24 hours
));
app.use((req, res, next) =>
const csrfTokenToSendToFrontEnd = req.csrfToken();
console.log('csrfTokenToSendToFrontEnd: ', csrfTokenToSendToFrontEnd);
// this cookie must be XSRF-TOKEN, because already defined as default in Angular.
res.cookie('XSRF-TOKEN', csrfTokenToSendToFrontEnd);
next();
);
// here requires the api file with all your rest apis (not static paths)
const routesApi = require('./src/routes/index')(express, passport);
app.use('/api', routesApi);
最后,在文件结束之前(在 500 中间件之前)我添加了这个来处理错误:
// error handler
app.use((err, req, res, next) =>
if (err.code !== 'EBADCSRFTOKEN')
return next(err);
res.status(403).json(
message: 'error'
);
);
我只复制了相关代码。如果您有任何问题,请随时询问,如果我忘记了什么,我会再次检查我的代码。
【讨论】:
不过,我也有同样的问题。我已经更新了我的问题并添加了更多详细信息 如果将所有路由(api)放在 csrf 之前,它如何保护? 你是对的。我从我的应用程序中复制了错误的 api(不受保护)。我更新了代码 今晚我会再检查一次,看看我是否忘记了什么。不过应该没问题。类似于 github 上的 csurf 官方示例 @jones 我更新了我的答案以使用 Angular 和 csurf 的默认值。我用 Chrome、Safari 和 Firefox 尝试了这段代码。它正在工作。另外,我在一个只有护照的应用程序中测试了这段代码,以防止干扰其他中间件。确保在进行 POST 之前有 cookie,如果没有尝试关闭浏览器的选项卡并重试。使用开发工具中“应用程序”选项卡下的按钮清理站点数据后,我在 chorme 上看到了一个奇怪的行为。以上是关于Node js csrf令牌保护不起作用的主要内容,如果未能解决你的问题,请参考以下文章
spring security 3.2.0 csrf 令牌在 freemarker 模板中不起作用
注册表单不起作用(CSRF 令牌丢失或不正确。) django
CSRF 令牌在带有 Ajax 请求的 Laravel 5.1 异常处理程序中不起作用