我已经以如下方式实现了csrf(跨站点请求伪造)保护:
... app.use(express.csrf()); app.use(function (req, res, next) { res.cookie('XSRF-TOKEN', req.csrfToken()); next(); }); ...
这很好。Angularjs在通过$ http服务发出的所有请求中都使用了csrf令牌。我通过我的角度应用程序发出的请求效果很好。
我的问题是测试这些api端点。我正在使用mocha来运行自动化测试,并使用request模块来测试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});