如何防止ExpressJS中的双重提交表单

时间:2015-09-13 06:21:28

标签: node.js post express submit

我遇到过网站上的人可以双重提交表单的问题。这不是数据库方面的问题,因为记录是通过服务器端验证保存的。但是,重要的是我使任何其他请求无效,以便用户不会被双重收费(因为收费发生在帐户之前)。我宁愿完全放弃请求,而不是重定向,因为它会破坏用户体验,而删除请求只会使进程“显得”更长,这是一个更好的妥协。

为了清理,我也在使用post-redirect-get模式,但它并没有解决这个问题,这实际上是最关键的问题,因为它是最常见的。实现客户端解决方案将是为了清洁UI,但我不能相信用户不禁用javascript或以某种方式篡改它。

我有一个使用库csurf的中间件解决方案,但不太有效。

var protect_route = function(req, res, next){
  if(!req.session.unique_requests){
    req.session.unique_requests = [];
  }

  var found = _.find(req.session.unique_requests, function(token){
    return token === req.body._csrf;
  });

  if(!found){
   req.session.unique_requests.push(req.body._csrf);
   next();
  } else {
   next('route'); //drop the post, and skip anything else.
  }
};

var unlock_route = function(req, res, next){
  req.session.unique_requests = _.without(req.session.unique_requests, req.body._csrf);
};

我将它附加到我的路线上:

router.post('/create', protect_route, function(req, res){
   // If it makes it in here, the route is protected and the 
   // request wasn't dropped.
});

router.get('/review', unlock_route, function(req, res){
   // The form will once again be able to be submitted.
});

不幸的是,即使中间件被调用,如果我混搭创建按钮,它会触发大量请求,每个请求都会尝试将令牌推送到unique_requests,结果是它不会阻止任何推送请求,直到一切都赶上来。

我在这里做错了什么,我该如何解决?

编辑:将POST限制为/ create似乎是一种可能,但我认为它似乎不像真正的解决方案。它可能会奏效。

1 个答案:

答案 0 :(得分:0)

     by using a simple session counter and set it as needed  in this example of 
     adding a role name single field string unique in schema definition
     counter field name is   rolesubmitcounter
     ///////////////////////////////////////////
     router.get('/add',ensureAuthenticated, function(req,res){
     req.session.rolesubmitcounter=0;
     res.render('roles/role_add',{
     title:"add role",
     nrole: {roleName:""}
     });
    });
    // Add Submit POST Route
     router.post('/add', ensureAuthenticated, function(req, res){
     if (req.session.rolesubmitcounter ===0){
     var tt1 =req.body.roleName.toString().trim();
    if(tt1==="".trim()){
    req.session.rolesubmitcounter=0;
       req.flash('danger','Role not..added.....may be empty fields......');
        res.render('roles/role_add', {
        title:'Add role',
        nrole: {roleName:req.body.roleName}
       });
      }
      else{
    ///////////////////////////////////////
    req.session.rolesubmitcounter = 1;
   let nrole = new Role();
   nrole.roleName = req.body.roleName.toLowerCase().trim();
   ///////////////////////////////////////////
   nrole.save(function(err){
    if(err){
      req.session.rolesubmitcounter=0;
       req.flash('danger','Role not..added.....may be duplicate key..');
       res.render('roles/role_add',{
       nrole: nrole
        });
      } else {
       req.flash('success','Role Added');
       res.redirect('/roles/roleindex');
       }
    });
    }
    }else{
     req.flash('danger','double submission Detected.....click once slowly');
     res.redirect('/roles/roleindex');
    }

   });