如何在测试后端api时处理csrf令牌

时间:2018-01-22 15:33:56

标签: javascript node.js express integration-testing csrf

运行单元/集成测试时,如何处理csrf中间件功能?我有一个位于Express后端API前面的Angular Web应用程序。所有后端路由都安装在csrf中间件之后,因此在测试期间,我总是遇到ForbiddenError: invalid csrf token错误。那么,哪一个看起来更合适:

  1. csrf
  2. 时不要启用process.env.NODE_ENV=test中间件
  3. 专门为测试环境公开一个单独的端点 检索csrf令牌并将其包含在每个request
  4. 示例1

    express.js

    const isProd = process.env.NODE_ENV === 'production';
    const isTest = process.env.NODE_ENV === 'test';
    
    if (!isTest) {
      app.use(csrf());
    }
    

    myTest.js

    it('should make a PATCH request', function() {
      // this would not throw any `invalid_csrf` token errors
      return request
        .patch('SOME_URL')
        .expect(200, 'some data')
    });
    

    示例2

    express.js

    const isProd = process.env.NODE_ENV === 'production';
    const isTest = process.env.NODE_ENV === 'test';
    
    // CSRF token. Angular needs it to be named 'XSRF-TOKEN'
    app.use(csrf());
    app.use((req, res, next) => {
      const _csrf = req.csrfToken();
    
      res.cookie('XSRF-TOKEN', _csrf, {
        secure: isProd,
        httpOnly: isProd
      });
    
      res.locals._csrf = _csrf;
      return next();
    });
    
    const router = require('./router')(app);
    

    router.js

    if (isTest) {
      app.use('/test/csrf', (req, res) => {
        res.json({
          csrfToken: res.locals._csrf
        });
      });
    }
    

    myTest.js

    const app = require('./app');
    const request = require('supertest')(app);
    
    // helper
    const cookies = (res) => {
      return res.headers['set-cookie'].map((cookies) => {
        return cookies.split(';')[0]
      }).join(';')
    };
    
    describe('example PATCH', function() {
      let response;
    
      // Use test endpoint to retrieve csrf token
      beforeEach(async () => {
        response = await request.get('/test/csrf');
      });
    
      // csrf token included (mimicking a client-side request), this will not throw an `invalid_csrf` token
      it('should make a PATCH request with a token', function() {
        return request
          .patch('SOME_URL')
          .set('Cookie', cookies(response))
          .set({
            'xsrf-token': response.body.csrfToken,
          })
          .expect(200, 'some data');
      });
    })
    

    所以我的问题是:当我为我的前端Angular应用程序提供后端api时,使用csrf中间件时我会使用哪种方法?

    使用的图书馆:

    csurfhttps://github.com/expressjs/csurf

    supertesthttps://github.com/visionmedia/supertest

1 个答案:

答案 0 :(得分:0)

这两种方法都可以,但是我还提出了方法3。

由于csurf(基于csrf)中的令牌对时间不敏感,因此您始终可以使用一对预定义的密钥+令牌进行单元测试。

const Token = require('csrf')
const token = new token()
const csrfToken = token.create('test')
console.log(csrfToken) // gaabrhn3--fmoXcOhmwoS6noe1TYvaDHzpYY

myTest.js

request
  .patch('SOME_URL')
  .set('Cookie', '_csrf=test')
  .set({
    'xsrf-token': 'gaabrhn3--fmoXcOhmwoS6noe1TYvaDHzpYY',
  })
  .expect(200, 'some data');