【问题标题】:On form submit, get CSRF via php file and pass the value to the request在表单提交时,通过 php 文件获取 CSRF 并将值传递给请求
【发布时间】:2015-05-18 15:21:33
【问题描述】:

如果符合条件,我将奖励这个问题 50 分。

我有一个投票系统,类似于在 SO 上的投票方式。

当用户通过<form> 投票时,我希望提交首先点击“get-csrf.php”以获取 CSRF 密钥,然后将该值传递给请求。

我怎样才能做到这一点?

jQuery 代码:

jQuery('.votetopicform').submit(ajaxSubmit_votetopicform);

function ajaxSubmit_votetopicform(){

var votetopicform = jQuery(this).serialize();

jQuery.ajax({
    type:"POST",
    url: SiteParameters.site_url+"/wp-admin/admin-ajax.php",
    data: votetopicform,
    success:function(data){
        jQuery(".feedback").html(data); // empty div to show returned data
    }
});

return false;
}

get-csrf.php 中,我有返回所需密钥的语句:

if (!isset($_SESSION['csrf'])) {
    $_SESSION['csrf'] = substr( md5(rand()), 0, 7);
}

return $_SESSION['csrf'];

所以,当用户点击提交时,我想通过我的 jQuery 代码获取 CSRF,然后将其发送到请求并在那里处理。

【问题讨论】:

  • 为什么需要这个预检请求?标准同步器令牌模式是否不够好? en.wikipedia.org/wiki/…
  • @Halcyon 长话短说,所有页面都被缓存(包括表单),所以我需要通过 JS 获取 CSRF 密钥,而不是简单地通过 html 直接在表单中添加密钥...
  • 你是在问如何链接请求?
  • @lxalmida 不确定该术语的含义。我在问:在提交表单时,我想点击 get-csrf.php,获取返回的密钥,然后通过表单发送它并在处理表单时使用该值。 (我的JS知识有限,所以这对于知道的人来说应该是一件容易的事)......

标签: javascript jquery forms


【解决方案1】:

我建议您这样做的方法是,首先在将表单交付给用户时将令牌放入隐藏的输入字段中。

<? if (!isset($_SESSION['csrf'])) { ?>
    <input type="hidden" name="csrf-token" value="<?= $_SESSION['csrf'] ?>">
<? } ?>

如果在您的情况下这不是一个可行的解决方案,您可以简单地链接请求。

jQuery('.votetopicform').submit(ajaxSubmit_requestcsrftoken);

function ajaxSubmit_requestcsrftoken(){
    jQuery.ajax({
        type:"POST",
        url: SiteParameters.site_url+"/get-csrf.php",
        success:function(data){
            ajaxSubmit_votetopicform(data);
        }
    });
}

您无需在提交表单时直接调用ajaxSubmit_votetopicform,而是调用一个首先请求csrf-token 的函数。服务器将令牌返回给所述函数,该函数调用发送实际提交并将返回的令牌作为参数传递给它的函数。

在您的 ajaxSubmit_votetopicform - 函数中,您现在只需将返回的令牌添加到请求中提交的数据中。

$.serialize() 返回一个 url 编码的字符串,您只需将其添加到字符串的末尾:

function ajaxSubmit_votetopicform(token){
   var votetopicform = jQuery(this).serialize();
   votetopicform += "&csrftoken=" + token; //token is passed as parameter to this fn

   ....
}

所以完整的 JavaScript - 代码如下所示:

//set the submit - event handler to a function, that requests the token first
jQuery('.votetopicform').submit(ajaxSubmit_requestcsrftoken);

function ajaxSubmit_requestcsrftoken(){
    jQuery.ajax({
        type:"POST",
        url: SiteParameters.site_url+"/get-csrf.php",
        success:function(data){
            // after succesfully requesting the CSRF - token, call the function 
            // that should submit the actual form data to your server and pass the token as parameter to it
            // this way you are chaining one request after the other
            ajaxSubmit_votetopicform(data);
        }
    });

    return false; //prevent the form from submitting
}

function ajaxSubmit_votetopicform(token){

    var votetopicform = jQuery(this).serialize();

    //add the token as additional parameter to be sent to the server
    votetopicform += "&csrftoken=" + token;

    jQuery.ajax({
        type:"POST",
        url: SiteParameters.site_url+"/wp-admin/admin-ajax.php",
        data: votetopicform,
        success:function(data){
            jQuery(".feedback").html(data); // empty div to show returned data
        }
    });
}

【讨论】:

  • 我的 JS 知识是有限的,所以对我来说是赤裸裸的。您能否更新您的答案并在最后添加完整的 jQuery 代码,包括我自己的 ajaxSubmit_votetopicform 代码,这样我就可以看到链接请求是如何工作的。
  • 好答案。另一种选择是在请求标头中包含 CSRF 令牌,但是,隐藏表单字段的方法是一种常见的做法。
  • @Brett 我喜欢这个选项,你应该写一个答案,概述如何将它包含在请求标头中。
  • @HenrikPetterson 添加了该部分。 @Brett 是的,这似乎也是一个好主意,$.ajaxPrefilter 会是解决这个问题的好方法,对吧?
  • 这是一个随请求传递的普通参数,与其他参数一样,因此您可能会通过 $_POST['csrftoken'] 之类的方式访问它
【解决方案2】:

GNi33 的回答是表单提交的一个很好的解决方案,对于这样的用例,我会推荐他的回答。我提出的解决方案也适用于表单;但是,对于非表单提交更为典型。这个想法是您在 HTTP 请求标头中包含 CSRF 令牌。

jQuery('.votetopicform').submit(ajaxSubmit_votetopicform);

function ajaxSubmit_votetopicform() {
  var votetopicform = jQuery(this).serialize();

  // chain AJAX requests
  jQuery.ajax({
    type: "GET",
    url: SiteParameters.site_url + "/wp-admin/get-csrf.php"
  }).then(function(token) {
    jQuery.ajax({
      type: "POST",
      url: SiteParameters.site_url + "/wp-admin/admin-ajax.php",
      data: votetopicform,
      headers: {
        "_RequestToken": token
      }
    });
  });

  return false;
}

【讨论】:

  • 有趣。但是,这是一个 ajax 形式,那么如何在处理请求的 php 函数中检索令牌?
  • 很好,但是,我如何在php函数中获取令牌?例如 $_POST['lorem']...
  • 搜索如何读取 PHP 中的所有 HTTP 标头变量。试试这个examplethis one。令牌的名称是您给它的名称,在本例中为 "_RequestToken"
猜你喜欢
  • 2016-07-24
  • 2015-01-20
  • 1970-01-01
  • 2014-02-02
  • 2013-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多