[英]How to test endpoints protected by csrf in node.js/express
我在快递中实现了csrf(跨站点请求伪造)保护,如下所示:
...
app.use(express.csrf());
app.use(function (req, res, next) {
res.cookie('XSRF-TOKEN', req.csrfToken());
next();
});
...
这非常有效。 Angularjs在通过$ http服务发出的所有请求中使用了csrf令牌。 我通过我的角度应用程序发出的请求非常好。
我的问题是测试这些api端点。 我正在使用mocha运行我的自动化测试和请求模块来测试我的api端点。 当我使用请求模块向使用csrf(POST,PUT,DELETE等)的端点发出请求时,即使它正确使用了cookie等,它也会失败。
还有其他人提出解决方案吗? 有人需要更多信息吗?
测试示例:
function testLogin(done) {
request({
method: 'POST',
url: baseUrl + '/api/login',
json: {
email: 'myemail@email.com',
password: 'mypassword'
}
}, function (err, res, body) {
// do stuff to validate returned data
// the server spits back a 'FORBIDDEN' string,
// which obviously will not pass my validation
// criteria
done();
});
}
诀窍是你需要将你的POST测试包装在GET中并从cookie中解析必要的CSRF令牌。 首先,假设您创建一个与Angular兼容的CSRF cookie,如下所示:
.use(express.csrf())
.use(function (req, res, next) {
res.cookie('XSRF-TOKEN', req.session._csrf);
res.locals.csrftoken = req.session._csrf;
next();
})
然后,您的测试可能如下所示:
describe('Authenticated Jade tests', function () {
this.timeout(5000);
before(function (done) {
[Set up an authenticated user here]
});
var validPaths = ['/help', '/products'];
async.each(validPaths, function (path, callback) {
it('should confirm that ' + path + ' serves HTML and is only available when logged in', function (done) {
request.get('https://127.0.0.1:' + process.env.PORT + path, function (err, res, body) {
expect(res.statusCode).to.be(302);
expect(res.headers.location).to.be('/login');
expect(body).to.be('Moved Temporarily. Redirecting to /login');
var csrftoken = unescape(/XSRF-TOKEN=(.*?);/.exec(res.headers['set-cookie'])[1]);
var authAttributes = { _csrf: csrftoken, email: userAttributes.email, password: 'password' };
request.post('https://127.0.0.1:' + process.env.PORT + '/login', { body: authAttributes, json: true }, function (err, res) {
expect(res.statusCode).to.be(303);
request.get('https://127.0.0.1:' + process.env.PORT + path, function (err, res, body) {
expect(res.statusCode).to.be(200);
expect(body.toString().substr(-14)).to.be('</body></html>');
request.get('https://127.0.0.1:' + process.env.PORT + '/bye', function () {
done();
});
});
});
});
});
callback();
});
});
我们的想法是实际登录并使用发布您从cookie中获取的CSRF令牌。 请注意,您需要在mocha测试文件的顶部添加以下内容:
var request = require('request').defaults({jar: true, followRedirect: false});
我所做的只是在非生产中暴露一个csrf令牌:
if (process.env.NODE_ENV !== 'production') {
app.use('/csrf', function (req, res, next) {
res.json({
csrf: req.csrfToken()
})
})
}
然后让它成为第一个测试并将其保存为全局测试。 您必须在测试中使用代理,以便始终使用相同的会话。
@dankohn的出色答案最有帮助。 关于supertest和csurf模块,事情已经发生了一些变化。 因此,除了答案之外,我发现需要将以下内容传递给POST:
it('should ...', function(done) {
request(app)
.get('/...')
.expect(200)
.end(function(err, res) {
var csrfToken = unescape(/XSRF-TOKEN=(.*?);/.exec(res.headers['set-cookie'])[1]);
assert(csrfToken);
request(app)
.post('/...')
.set({cookie: res.headers['set-cookie']})
.send({
_csrf: csrfToken,
...
})
.expect(200)
.end(done);
});
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.