[英]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.