簡體   English   中英

如何在node.js / express中測試受csrf保護的端點

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM