如何测试使用 mocha/chai 的 csurf csrf 保护的 http api?

How to test http api that uses csurf csrf protection with mocha/chai?

不是 this one

的副本

我想知道要测试使用 csurf csrf 保护的 api 需要设置的最低 headers/cookies 是多少。

在我的服务器中我有:

const app = express()

const csrfMiddleware = csurf({
    cookie: true
})

app.use(cookieParser())
app.use(csrfMiddleware)
app.get('/singup', ...)
app.post('/singup', ...)

在测试文件中:

const chai = require('chai')
const chaiHttp = require('chai-http')
chai.use(chaiHttp);
const request = chai.request;
const expect = chai.expect;

const cheerio = require('cheerio')
const app = "http://localhost:3000" 

function extractCsrfToken(res) {
    var $ = cheerio.load(res.text);
    return $('[name=_csrf]').val();
   }

describe('Post Endpoints', () => {
  it('should create a new user', () => {
        request(app).get('/singup').end((err, resGet)=>{
          expect(err).to.be.null;
          expect(resGet).to.have.status(200)
          const _csrf = extractCsrfToken(resGet);

          console.log(`sending request with csrf token ${_csrf}`)
          request(app)
          .post('/singup')
          .set('Cookie', `_csrf=${_csrf}`)
          .set('Connection', 'keep-alive')
          .set('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8')
          .send({
              username: "teste-automatizado",
              email: 'some-email@example.com',
              password: '12345678',
              passwordConfirm: '12345678'
      
          }).end((err2, res)=>{
            expect(err2).to.be.null;
            expect(res).to.have.status(200)
          })
          
        })   
  })
})

我期望的是创建用户和来自 POST 请求的 200 return 这没有发生,因为它失败了来自中间件的 403:

$ npm test

> app@1.0.0 test
> mocha



  Post Endpoints
    ✔ should create a new user


  1 passing (21ms)

sending request with csrf token PDwitHYN-ttgB5zAIGCQqq9cCxgwkbXyyrMM

/home/fabio/src/project/node_modules/mocha/lib/runner.js:962
    throw err;
    ^
AssertionError: expected { Object (_events, _eventsCount, ...) } to have status code 200 but got 403
    at /home/fabio/src/project/test.js:37:33
    at Test.Request.callback (/home/fabio/src/project/node_modules/superagent/lib/node/index.js:716:12)
    at IncomingMessage.<anonymous> (/home/fabio/src/project/node_modules/superagent/lib/node/index.js:916:18)
    at IncomingMessage.emit (node:events:402:35)
    at endReadableNT (node:internal/streams/readable:1343:12)
    at processTicksAndRejections (node:internal/process/task_queues:83:21) {
  showDiff: true,
  actual: 403,
  expected: 200
}

根据 documentation,令牌应位于名为 CSRF-Token 的 header 中。

request(app)
  .post('/singup')
  .set('CSRF-Token', _csrf)
...

此外,您可能需要根据第一个请求的响应设置 Cookie header on your request. But you should use the value of the Set-Cookie header。

为此,chai 可以选择 retain the cookies。关键是使用代理来发出所有请求。

const agent = chai.request.agent(app)

agent.get('/singup').end((err, res) => {
  // do some tests and get the token
  // ...
  // the agent will use the cookie from the previous request
  // so you only need to set the CSRF-Token header 
  agent.post('/singup')
    .set('CSRF-Token', _csrf)
    .send({ username: 'me', password: '123' })
    .end((err, res) => {
       // handle the post response 
    })
})

agent.close()