2017-04-17 168 views
0

我有一个CSRF预防的简单标记,它在不使用AJAX提交时按预期工作。但是当使用AJAX时,它会一直显示我创建的自定义错误。当使用AJAX提交表单时,CSRF令牌不起作用

这是我生成令牌功能:

function make_form_token() { 
    $token = base64_encode(openssl_random_pseudo_bytes(32)); 
    $_SESSION['token'] = $token; 
    return $token; 
} // end CSRF token generation 

的功能,然后调用名为隐藏字段form_token

<form id="contact-form" method="post"> 
    <input type="hidden" name="form_token" value="<?php echo make_form_token(); ?>"> 

    <div class="col-sm-5 col-md-4 col-xs-6"> 
     <button id="send" type="submit" name="submit" class="btn btn--primary type--uppercase">Send Enquiry</button> 
    </div> 
</form> 

然后Ajax调用从PHP脚本接触提交。 PHP

$(document).ready(function(){ 
    $("#send").click(function(){ 
     $("#send").prop("disabled", true); 
     $(".hideloader").show(); 
     $("#send").html("Sending <img src='img/ajax-loader.gif'>"); 

     var form_data = $("#contact-form").serialize(); 

     $.ajax({ 
      type: 'POST', 
      url: 'contact-submit.php', 
      data: form_data 
     }).done(function(response) { 
      $("#server-results").hide().html(response).fadeIn("slow"); 
      $("#send").prop("disabled", false); 
      $("#send").html("Send Enquiry"); 
     }); 
    }); 
}); 

接触submit.php

if ($_SERVER["REQUEST_METHOD"] == "POST") { 

    $message = ""; 

    if (!isset($_SESSION['token']) || $_POST['form_token'] !== $_SESSION['token']) { 
     $message .= "There was an error submitting the form. Please try again later. <br/>"; 
    } 

    if ($message) { 
     echo "<div class='red-error'><b>There were errors in your form:</b> <br/>" . $message . "</div>"; 
    } else {  
     // send email etc. 
    } 
} 
+0

你能的var_dump $ _ POST [ 'form_token']和$ _SESSION [ '令牌']?他们是一样的吗? –

+0

当尝试的var_dump我得到这个: 注意:未定义的变量:/应用程序/ MAMP/htdocs中/上线11 空字符串_SESSION(44) “HBFYoXNsHS9WsBc7vds/MukXr0CR8pBFPc7WGi3JPvY =” – Jonathan

+1

是您的会议开始时,POST请求到达服务器? –

回答

0

我想我知道你的问题是什么。让我知道如果我错了。你有这样的HTML:在页面加载

<form id="contact-form" method="post"> 
<input type="hidden" name="form_token" value="<?php echo make_form_token(); ?>"> 
<div class="col-sm-5 col-md-4 col-xs-6"> 
<button id="send" type="submit" name="submit" class="btn btn--primary type--uppercase">Send Enquiry</button> 
</div> 
</form> 

生成此HTML,但我认为这是对POST产生一样,所以当您在form随着有效form_token柱与该请求到达服务器,它会生成一个新的标记(当生成HTML时),将其存储到$ _SESSION中,这与它在页面加载时生成的标记不同。当且仅当您的请求是GET时,解决方案是生成form

编辑:确保当POST请求到达服务器时启动会话。

EDIT2:这是你可以检查你的请求是否是POST:

if ($_SERVER['REQUEST_METHOD'] === 'POST') { 
    // The request is using the POST method 
} 
+0

但我不明白为什么它不起作用。我一直使用这个不使用AJAX的表单,它可以100%工作。只有现在使用AJAX时,它给了我这个问题 – Jonathan

+0

@Jonathan我认为你的HTML代码覆盖会话中存储的令牌,在服务器接收到POST之后调用,然后它会比发布值更经常。 –

+0

谢谢。如果你看我的原始帖子,我已经有POST检查(我只有一个比你更少) if($ _SERVER ['REQUEST_METHOD'] =='POST'){ – Jonathan