car*_*iem 2 testing csrf mocha.js supertest sails.js
我有一个几乎全新的 Sails.js 1.0.2 应用程序,我可以使用浏览器和 Postman 登录。但是,我似乎无法在我的测试运行器中执行相同的过程。
下面的测试应该会导致成功登录,其中会返回一个带有新会话 ID 的 cookie。如果我更改安全配置以禁用CSRF 保护,它会完美运行。但是在启用安全性的情况下,请求被禁止 (403)。我在 Postman 中发送的内容之间唯一的实质性区别似乎是 mocha 在不同的端口上运行应用程序(Postman 发送到localhost:1337, express' res 变量说PUT /api/v1/entrance/login HTTP/1.1 Host: 127.0.0.1:56002
有人看到我遗漏的东西吗?
这是测试文件:
/**
* /test/integration/controllers/entrance/login.test.js
*/
'use strict';
const supertest = require('supertest'); // also tried supertest-session
describe('Entrance controllers', () => {
describe('/api/v1/entrance/login', () => {
before(() => {
return supertest(sails.hooks.http.app)
.get('/login')
.then(res => {
const reTokenCapture = /_csrf:\s*unescape\('([^']+)'\)/;
const found = reTokenCapture.exec(res.text);
this._csrf = sails.config.security.csrf ? found[1] : '';
this.url = '/api/v1/entrance/login';
});
});
it('should return a session cookie in response headers', () => {
return supertest(sails.hooks.http.app)
.put(this.url)
.set('x-csrf-token', this._csrf)
.send({
emailAddress: 'admin@example.com',
password: 'abc123',
// _csrf: this._csrf, // I tried this too; no luck
})
.expect(200) // if sails.config.security.csrf is enabled, status is 403
.then(res => {
// console.log('res:', res); // this shows the correct header
res.headers['set-cookie'].should.be.an('array');
const hasSid = res.headers['set-cookie'].map(cookie => {
const reSid = /^sails\.sid=[^;]+;\sPath=\/;(?:\sExpires=[^;]+GMT;)?\sHttpOnly$/;
return reSid.test(cookie);
});
hasSid.should.include.members([true]);
});
});
});
});
Run Code Online (Sandbox Code Playgroud)
我正在运行 node v8.11.3、sails v1.0.2、mocha v5.2.0、supertest v3.1.0、chai v4.1.2
仅供参考,这是 Postman 提出的请求,运行良好(CSRF 令牌是由之前的 Postman 请求手动复制到 的GET /login):
PUT /api/v1/entrance/login HTTP/1.1
Host: localhost:1337
x-csrf-token: mjWXQTa2-RFEHu78Tr-JGJwhWeryKGRJI4S8
Cache-Control: no-cache
Postman-Token: e3d920fe-6178-4642-80e4-8005b477fd98
{"emailAddress": "admin@example.com", "password":"abc123"}
Run Code Online (Sandbox Code Playgroud)
知道了!我以为我打算set-cookie在登录后从标题中获取会话 ID 。相反,我打算在注销时同时捕获 CSRF 令牌和会话 ID,然后提交电子邮件和密码,然后在中使用令牌和 ID后续请求。我错过了 Postman 中的这个细节,因为我没有注意到请求之间持续存在的 cookie。
这是固定的测试文件(现在启用 CSRF 保护):
/**
* /test/integration/controllers/entrance/login.test.js
*/
'use strict';
const supertest = require('supertest'); // also tried
describe('Entrance controllers', () => {
describe('/api/v1/entrance/login', () => {
before(() => {
this._url = '/api/v1/entrance/login';
return supertest(sails.hooks.http.app).get('/login')
.then(getRes => {
const reTokenCapture = /_csrf:\s*unescape\('([^']+)'\)/;
const foundToken = reTokenCapture.exec(getRes.text);
this._csrf = sails.config.security.csrf ? foundToken[1] : '';
this._cookie = getRes.headers['set-cookie'].join('; ');
});
});
it('should accept the session ID & CSRF token procured by GET /login', () => {
return supertest(sails.hooks.http.app)
.put(this._url)
.set('Cookie', this._cookie)
.set('X-CSRF-Token', this._csrf)
.send({
emailAddress: 'admin@example.com',
password: 'abc123',
})
.expect(200);
});
it('should reject requests without a CSRF token', () => {
return supertest(sails.hooks.http.app)
.put(this._url)
.set('Cookie', this._cookie)
.expect(403);
});
it('should reject requests without a session cookie', () => {
return supertest(sails.hooks.http.app)
.put(this._url)
.set('Cookie', '')
.set('x-csrf-token', this._csrf)
.expect(403);
});
it('should reject requests with invalid tokens', () => {
return supertest(sails.hooks.http.app)
.put(this._url)
.set('Cookie', 'sails.sid=foo; Path=/; HttpOnly')
.set('X-CSRF-Token', 'foo')
.send({
emailAddress: 'admin@example.com',
password: 'abc123',
})
.expect(403);
});
it('should reject requests with invalid credentionals', () => {
return supertest(sails.hooks.http.app)
.put(this._url)
.set('Cookie', this._cookie)
.set('X-CSRF-Token', this._csrf)
.send({
emailAddress: 'user@example.com',
password: 'password'
})
.expect(401);
});
it('should reject get requests', () => {
return supertest(sails.hooks.http.app)
.get(this._url)
.set('Cookie', this._cookie)
.set('X-CSRF-Token', this._csrf)
.send({
emailAddress: 'admin@example.com',
password: 'abc123',
})
.expect(404);
});
it('should reject post requests', () => {
return supertest(sails.hooks.http.app)
.post(this._url)
.set('Cookie', this._cookie)
.set('X-CSRF-Token', this._csrf)
.send({
emailAddress: 'admin@example.com',
password: 'abc123',
})
.expect(404);
});
});
});
Run Code Online (Sandbox Code Playgroud)