Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/38.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在node.js/express中测试受csrf保护的端点_Node.js_Angularjs_Express_Request_Csrf - Fatal编程技术网

如何在node.js/express中测试受csrf保护的端点

如何在node.js/express中测试受csrf保护的端点,node.js,angularjs,express,request,csrf,Node.js,Angularjs,Express,Request,Csrf,我在express中实施了csrf(跨站点请求伪造)保护,如下所示: ... app.use(express.csrf()); app.use(function (req, res, next) { res.cookie('XSRF-TOKEN', req.csrfToken()); next(); }); ... 这很有效。Angularjs在通过$http服务发出的所有请求中都使用csrf令牌。我通过angular应用程序提出的请求非常有效 我的问题是测试这些api端点。我使用mo

我在express中实施了csrf(跨站点请求伪造)保护,如下所示:

...
app.use(express.csrf());
app.use(function (req, res, next) {
  res.cookie('XSRF-TOKEN', req.csrfToken());
  next();
});
...
这很有效。Angularjs在通过$http服务发出的所有请求中都使用csrf令牌。我通过angular应用程序提出的请求非常有效

我的问题是测试这些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();
  });
}

我要做的是仅在非生产环境中公开csrf令牌:

if (process.env.NODE_ENV !== 'production') {
  app.use('/csrf', function (req, res, next) {
    res.json({
      csrf: req.csrfToken()
    })
  })
}

然后将其作为第一个测试,并将其保存为全局。您必须在测试中使用代理,以便始终使用相同的会话。

诀窍在于,您需要将测试后的内容包装在GET中,并从cookie中解析必要的CSRF令牌。首先,假设您创建一个角度兼容的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();
  });
});
然后,您的测试可以如下所示:

.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();
  });
});
他出色的回答非常有帮助。从那时起,supertest和模块的情况都发生了一些变化。因此,除了这个答案外,我还发现需要将以下内容传递给该职位:

  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);
      });
  });

你能把你尝试做的测试的样本放在上面吗?然后我将如何在我的请求中使用csrf令牌?如果我将jar:true添加到请求对象,它使用cookies,我可以看到正在使用的令牌和cookie,但出于某种原因,它不接受它。那么我如何在请求中使用令牌使其接受它呢?您必须提交它。ie
x-csrf-token:csrf
或将其添加到请求正文中。是的,这很烦人,但这正是用户必须做的。确保会话不会在每次请求时都更改。我已经在测试端和服务器端注销了请求和响应对象,并且令牌在顺序请求中是相同的。它就在那里,就像我使用站点前端访问相同端点时一样。cookie就在那里,并且在第一个请求之后的每个请求中都会添加到请求体中。这种“麻烦”是好的,因为这是一种测试,可以确保表单确实需要csrf进行验证,并且不会忽略它。我不喜欢这种方法,因为你必须事先提出要求。但是我想不出一个不启动会话就获取(或存根)令牌的好方法。看起来就是这个方法。我希望我不必嵌套这样的请求,所以我可以在运行测试时禁用csrf。这当然有点痛苦,但如果你不使用csrf,你就无法实际进行端到端测试。这是真的。。。我还考虑过使用一个不同的测试框架,比如phantomjs,在这里我可以测试更多和应用程序的交互,而不仅仅是端点,但我想两者都可以。谢谢你的帮助!它与node.js配合得非常好!感谢分享您对cookies使用的想法!如果XSRF-TOKEN cookie不可用,并且您不希望将其添加到服务器中,则可以使用
res.text.match(/name=_csrfvalue=([^>]*)>)>/)[1]
从登录页的html表单获取csrf令牌。