NodeJS Express应用程序测试 - 如何在使用Mocha和Chai进行测试时提交CSRF令牌?
问题描述:
我正尝试使用Mocha,Chai和ChaiHttp在我的Express应用程序中编写POST
路由的测试,但由于事实上我无论何时提交我的CSRF令牌都会收到响应,我无法正常工作。下面是我到目前为止的代码:NodeJS Express应用程序测试 - 如何在使用Mocha和Chai进行测试时提交CSRF令牌?
express.js配置文件
...
app.use(session(config.SESSION));
// csrf is the 'csurf' module
app.use(csrf());
app.use((req, res, next) => {
res.cookie('XSRF-TOKEN', req.csrfToken());
return next();
});
...
User.test.js
'use strict';
process.env.NODE_ENV = 'test';
const User = require('../server/models/User');
const chai = require('chai');
const chaiHttp = require('chai-http');
const server = require('../index');
const utils = require('../utils');
chai.use(chaiHttp);
describe('Users',() => {
beforeEach((done) => {
User.remove({}, (err) => {
done();
});
});
after((done) => {
server.close();
done();
});
...
/*
* [POST] /user
*/
describe('[POST] /user',() => {
it('should return a JSON object with a "success" property equal to "true" when creating a new user', (done) => {
const userObj = utils.generateUserObject();
chai.request(server)
.get('/api')
.end((error, response) => {
userObj._csrf = utils.extractCsrfToken(response.headers['set-cookie']);
/*
* Accurately logs the _csrf property with the correct CSRF token that was retrieved via the initial GET request
*
* Example output:
*
* {
* username: 'Stacey89',
* first_name: 'Gregg',
* last_name: 'King',
* ...
* _csrf: 'vBhDfXUq-jE86hOHadDyjgpQOu-uE8FyUp_M'
* }
*
*/
console.log(userObj);
chai.request(server)
.post('/api/user')
.set('content-type', 'application/x-www-form-urlencoded')
.send(userObj)
.end((err, res) => {
res.should.have.status(200);
res.body.should.be.a('object');
res.body.should.have.property('success').eql('true');
done();
});
});
});
...
utils.js
...
extractCsrfToken(cookiesObj) {
const cookiesArray = Array.prototype.join.call(cookiesObj, '').split(';');
let csrfToken = 'NOT FOUND';
cookiesArray.forEach((cookie) => {
if (cookie.includes('XSRF-TOKEN')) {
csrfToken = cookie.split('=').splice(1, 1).join('');
}
});
return csrfToken;
}
...
当我运行上面的测试,我得到以下错误:
ForbiddenError: invalid csrf token
...
POST /api/user 403
奇怪的是,如果我从邮递员用完全相同的配置如前所述的一个POST请求,我顺利拿到回应我正在寻找和表单提交成功。
从我的测试套件中提交userObj
似乎不工作。
UPDATE#1 我终于设法找到了适合我的问题的解决方案。
我已经更新了先前的XSRF-TOKEN
的cookie设置为以下中间件:
app.use((err, req, res, next) => {
res.locals._csrf = req.csrfToken();
return next();
});
现在的单元测试运行成功。
此外,我注意到,向服务器发出第一[GET]
请求返回Set-Cookie
头:
Status Code: 200 OK
Content-Length: 264
Content-Type: application/json; charset=utf-8
Date: Tue, 18 Oct 2016 12:10:09 GMT
Etag: W/"108-NSQ2HIdRqiuMIf0F+7qwjw"
Set-Cookie: connect.sid=s%3Ap5io8_3iD7Wy0X0K77qWZLoYj-fD1ZbA.6uvcBiB%2B%2BSi1KOVOmJgvWe%2B5Mqpuc1rs9yUYxH0uNPY; Path=/; HttpOnly
X-Download-Options: noopen
X-XSS-Protection: 1; mode=block
x-content-type-options: nosniff
x-dns-prefetch-control: off
x-frame-options: SAMEORIGIN
任何后续[GET]
请求不返回头:
Status Code: 200 OK
Content-Length: 264
Content-Type: application/json; charset=utf-8
Date: Tue, 18 Oct 2016 12:11:19 GMT
Etag: W/"108-NSQ2HIdRqiuMIf0F+7qwjw"
X-Download-Options: noopen
X-XSS-Protection: 1; mode=block
x-content-type-options: nosniff
x-dns-prefetch-control: off
x-frame-options: SAMEORIGIN
这是正常的应用安全条款?只需在res.locals
对象上设置_csrf
标记是否是一种很好的做法?
答
chai-http的send()方法用于发送json(通常需要使用json主体解析器)。因此,您不应该将内容类型设置为application/x-www-form-urlencoded
。
如果你没有使用JSON解析器身体和你真的想寄的表格数据,该field() method应该工作:
chai.request(server)
.post('/api/user')
.field('_csrf', _csrf)
.end((err, res) => {
res.should.have.status(200);
res.body.should.be.a('object');
res.body.should.have.property('success').eql('true');
done();
});
我并不想通过cookie来把它 - 我发送_csrf标记作为'req.body'的一部分 –