防止重复的表单提交

时间:2011-01-06 14:15:46

标签: php forms submit

我提出了一种技术,可以通过返回/转发或刷新页面来防止重复表单提交。我想在这里讨论它,我已经测试了一个不在生产环境中的样本,你可以识别的缺陷是什么?

请注意,我很清楚使用表单令牌,它会保护您免受CSRF攻击,并且未在以下步骤中添加。

- 为每个表单生成表单ID,并将其用作表单中的隐藏字段:

$formid = microtime(true)*10000;

- 表单提交

  • 从数据验证

  • 计算表单字段数据的哈希值

    $allvals = '';
    foreach($_POST as $k=>$v){
        $allvals .= $v;
    }
    $formHash = sha1($allvals);
    
  • 通过与之前保存的哈希进行比较来验证表单哈希。会话值通过$ formid变量绑定到每个表单。

    $allowAction = true;
    if(isset($_SESSION['formHash'][$_POST['formid']]) && ($_SESSION['formHash'][$_POST['formid']] == $formHash)){
         $allowAction = false;
    }
    
  • 如果找不到表单哈希,则表示这是第一次提交表单或更改表单数据。
  • 如果保存了数据(例如,保存到数据库),请将表单哈希保存到会话:

    $_SESSION['formHash'][$_POST['formid']] = $formHash;
    

完整版代码: http://thebusy.me/2011/01/06/preventing-duplicate-form-submissions/

3 个答案:

答案 0 :(得分:7)

实现您想要的更简单的方法是在提交时使用重定向。处理POST请求后,您可以重定向,甚至可能重定向到同一页面。这是一种称为“POST后重定向”或POST/Redirect/GET的常见模式。

例如:

<?php
if($_POST) {
    // do something

    // now redirect
    header("Location: " . $_SERVER["REQUEST_URI"]);
    exit;
}
?>

<html> ...
<form method="post" action=""> ... </form>

通过将操作设置为“”,它将提交给自己,此时if($ _ POST)代码块将验证为true并处理表单,然后重定向回自身。

当然,您可能希望重定向到显示“您的表单已提交”响应的其他页面,或将表单放在不同的页面上,并将此页面的HTML作为响应。

此方法的好处是,当您点击后退按钮时,它会执行GET请求,因此不会重新提交表单。

在Firefox上,它实际上会将提交内容从浏览器历史记录中删除,因此当用户浏览网页然后回滚时,他们会看到表单页面,而不是看到“谢谢”页面。

答案 1 :(得分:1)

看起来你变得过于复杂了。我最喜欢的方式是,因为它也可以同时防止一些会话攻击,这里描述:

http://www.spotlesswebdesign.com/blog.php?id=11

在任何形式上都很容易实现。它使用随机生成的页面实例ID来验证收到的表单提交是否与提供给该特定用户的最后一页相同。

答案 2 :(得分:-1)

上述两种解决方案都很好,但有点短。

如何在同一个用户的下几分钟内停止进一步的插入,可能会对数据进行微小的更改?

这可以通过在用户计算机上的cookie中放入md5哈希并将副本存储在数据库中来实现 - 这样可以忽略来自同一台计算机在指定时间内的任何进一步尝试,并停止插入数据库中。

也许有人可以对我的建议的有效性和有效性发表评论,或者我是在咆哮错误的树????