首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >防止Ajax表单在php中使用表单令牌进行双重提交

防止Ajax表单在php中使用表单令牌进行双重提交
EN

Stack Overflow用户
提问于 2018-07-17 09:28:34
回答 3查看 273关注 0票数 0

*更新*

我的代码似乎没有什么问题;因为用完全相同的代码创建一个新文档完全正常。所以文件可能以某种方式损坏了。参见my answer below

我无论如何也找不到任何相关的问题或问题。基本上,我有一个审查表单,通过Ajax发送到一个php进程页面。验证后,将数据插入到mySQL数据库中。Ajax将信息(主要是错误)发送回用户。我需要一种方法来防止在服务器端使用php的多个提交。

我尝试过使用表单令牌,它在没有Ajax的情况下可以工作,但不能与Ajax一起使用。$_SESSION似乎没有带到表单处理程序的页面上。

这个问题... $_SESSION['review_form_token']根本没有保存任何数据。如果我在错误中打印会话数据,它根本不会打印任何东西!然而,我有一个使用会话的php captcha,它可以毫无问题地打印出来。当我在页面加载时设置会话时,它会按照预期将令牌打印到隐藏输入中。我不明白为什么表单令牌不能传递到表单进程。这两个文档上都有session_start()。我已经尝试过ob_start()了,但是没有用。请帮我调试一下。

这是我的简化设置...

index.php (在顶部):

代码语言:javascript
复制
<?php
session_start();
$reviewForm_token = md5(uniqid(rand(), true));
$_SESSION['review_form_token'] = $reviewForm_token;
?>

index.php -表单(某处)

代码语言:javascript
复制
<form id="reviewform" method="post" novalidate>
   <input type="text" class="form-control form-style name" name="firstname" size="15" maxlength="40" autocomplete="given-name">
   <input type="text" class="form-control form-style name" name="lastname" size="15" maxlength="40" autocomplete="family-name">                 
    <textarea class="form-control form-style" name="review" minlength="50" required></textarea>                 
    <input type="text" class="form-control form-style" name="captcha" autocomplete="off" maxlength="6" required>
    <img src="https://via.placeholder.com/200x60" id="captcha-review" alt="Review captcha image" width="200" height="60">

    <input type="hidden" name="form_token" value="<?php echo $_SESSION['review_form_token']; ?>">
    <button type="submit" name="submit" class="btn btn-primary submit float-right font">Send</button>
    <button type="reset" class="btn btn-primary reset font">Reset</button>
</form> <!-- End form -->

index.php - Ajax (在文档底部)

代码语言:javascript
复制
$('#reviewform').submit(function(event) {
// Set some variables
var $this = this,
    firstnameInput = $('input[name=firstname]', $this),
    lastnameInput = $('input[name=lastname]', $this),
    nameInput = $('input.name', $this),
    ratingInput = $('input[name=StarRating]', $this),
    ratingInputChecked = $('input[name=StarRating]:checked', $this),
    stars = $('.star-rating', $this),
    reviewInput = $('textarea[name=review]', $this),
    captchaInput = $('input[name=captcha]', $this),
    form_tokenInput = $('input[name=form_token]', $this),
    submitButton = $("button.submit", $this);

// Get the form data
// Must relate to the name attribute...
var formData = {
    'firstname': firstnameInput.val(),
    'lastname': lastnameInput.val(),
    'StarRating': ratingInputChecked.val(),
    'review': reviewInput.val(),
    'captcha': captchaInput.val(),
    'form_token': form_tokenInput.val(),
};
// Process the form
$.ajax({
        type: 'POST', // Define the type of HTTP verb we want to use (POST for our form)
        url: 'formProcess-review.php', // The url where we want to POST
        data: formData, // Our data object
        dataType: 'json', // What type of data do we expect back from the server
        encode: true
    })
    .done(function(data) {
        // Here we will handle errors and validation messages
        if (!data.success) {

            // Handle errors for doublepost (form_token) ---------------
            if (data.errors.doublepost) {
                $('button', $this).parents('.form-row')
                    .append(label + data.errors.doublepost + '</label>')
                    .children('label.invalid').attr('id', 'doublepost-error');
            }
        } else {
            // SUCCESS!!
           // Thanks!
        }
    }); // End .done function
// Stop the form from submitting the normal way and refreshing the page
event.preventDefault();
}); // End .submit function

formProcess-review.php

代码语言:javascript
复制
<?php
session_start();
$errors     = array(); // array to hold validation errors
$data       = array(); // array to pass back data
$firstname  = $_POST['firstname'];
$lastname   = $_POST['lastname'];
$StarRating = $_POST['StarRating'];
$review     = $_POST['review'];
$captcha    = $_POST['captcha'];

// Form Validation...

if ($_POST['form_token'] !== $_SESSION['review_form_token']) {
   $errors['doublepost'] = 'You have already submitted your review, you can not resubmit. If you need to send another review, please reload the page.';
}
// return a response ===========================================================
// if there are any errors in our errors array, return a success boolean of false
if (!empty($errors)) {
   // if there are items in our errors array, return those errors
   $data['success'] = false;
   $data['errors']  = $errors;
} else {
   // if there are no errors process our form, then return a message

   unset($_SESSION['review_form_token']);

   // mySQL inserting data...

   // show a message of success and provide a true success variable
   $data['success'] = true;
   $data['message'] = 'Success!';
}
// return all our data to an AJAX call
echo json_encode($data);
?>
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-07-26 05:22:39

jun drie's anwser给了我动力,让我用同样的代码创建一个全新的index.php;这似乎是可行的。我不知道为什么或如何,但原始文件一定已经损坏,迫使它不能正常工作,但仍然使它在网络上显示(奇怪,嗯?!)

我已经编辑了我的代码,使之更简单化,希望更好。

我在取消设置会话时遇到了问题,所以我现在在index.php中的session_start();之后直接调用session_unset();,从1次重新加载之前取消设置任何以前的会话。

虽然我已经做了这个改变,但奇怪的是,它过去没有它也能工作。

票数 0
EN

Stack Overflow用户

发布于 2018-07-17 10:18:24

我刚刚测试了您的代码,表单令牌会话令牌都可以在formProcess-review.php上正确捕获。你的代码一定有其他问题导致了它。

简化的Ajax提交。

代码语言:javascript
复制
$.ajax({
        type: 'POST', 
        url: 'formProcess-review.php', 
        data: formData, 
        dataType: 'json', 
        encode: true
    })
    .done(function(data) {
  		alert(data.message);
      
    });

简化的表单流程-review.php

代码语言:javascript
复制
<?php
session_start();
$data['message'] = "Form token = ".$_POST['form_token']."   Session value = ".$_SESSION['review_form_token'];
echo json_encode($data);
die();
?>

票数 1
EN

Stack Overflow用户

发布于 2018-07-17 10:01:02

尝试将此选项“withCredentials”添加到ajax调用:

代码语言:javascript
复制
$.ajax({
    type: 'POST', 
    url: 'formProcess-review.php', 
    data: formData, 
    dataType: 'json', 
    encode: true,
    xhrFields: {
      withCredentials: true
    }
}

可能是ajax调用没有将会话cookie发送到服务器。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51371991

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档