php 你如何确保 $_POST 数据来自你的表单而不是外部影响?

Posted

技术标签:

【中文标题】php 你如何确保 $_POST 数据来自你的表单而不是外部影响?【英文标题】:php How do you ensure $_POST data is coming from your form and not a outside influence? 【发布时间】:2012-05-18 15:03:39 【问题描述】:

有没有办法确保我的代码收到的$_POST 数据来自我的表单,而不是外部影响。基本上我不希望有人能够将$_POST 欺骗到一个普遍可用的页面,例如帐户创建。任何用户都可以访问帐户创建页面,但我想确保只有我的 account_creation 表单提交的数据才会得到处理。

我唯一能想到的就是启动$_SESSION,然后使用隐藏输入将 session_id 提供给表单。在 $_POST 之后,隐藏输入的值将与当前 session_id 匹配。

如果有更好的方法来达到这个结果?如果有我期待听到它。

【问题讨论】:

【参考方案1】:

您无法确保数据来自表单。 POST 请求只是一个 POST 请求,它可以通过多种方式生成。 html 表单只是一种非常用户友好的方式。您的服务器需要验证通过 POST 请求接收到的数据是否有效以及是否对其进行操作。

话虽如此,有些东西可以帮助您限制和验证正在提交的数据。首先,要求用户使用(会话)cookies 登录。这消除了匿名用户的随机请求。其次,您可以将令牌作为隐藏字段嵌入到您也保存到用户会话中的表单中。 POST 请求需要包含该令牌才能有效。令牌只是一个伪随机字符串。 您可以通过准备您希望用户提交的表单字段的哈希来增强这一点。如果表单值应该是只读的,您也可以将该值包含到散列中。例如:

$rand = md5(mt_rand());
$hash = sha1('lastname:firstname:email:' . $rand);

$_SESSION['rand'] = $rand;
$_SESSION['hash'] = $hash;

// on form submit:

$keys = array_keys($_POST);
$checkHash = sha1(join(':', $keys) . ':' . $_SESSION['rand']);
if ($checkHash != $_SESSION['hash']) 
    die('Form submission failed token validation');

这只是一个简单的示例,您可能希望按字母顺序对键进行排序,以确保获得相同的哈希值等。它演示了用户需要为每个请求拥有唯一令牌的概念,但这会阻止修改表单并提交比预期更多或更少的数据。

但这并不意味着用户实际上使用了您的表单来提交数据。

【讨论】:

【参考方案2】:
$ref = $_SERVER['HTTP_REFERER'];
if($ref !== 'some site path/index.php')

    die("Access Denied!");

这应该可以防止大多数人将数据发布到您的数据库中,以免受到外部影响。

【讨论】:

我很惊讶你没有被“可以被欺骗”的悲观主义者淹没【参考方案3】:

稍微好一点的是添加额外的验证,例如 user_agent、user_ip 和其他一些 $_SERVER 变量——我使用的就是这两个。

因此,按照您的描述创建唯一 ID(或会话 ID),但添加一些额外的验证,即代理和 ip 也匹配。不是万无一失,但增加了另一层安全性。

编辑:我应该补充一点,您不会将用户代理发回;保留该服务器端并根据返回的会话 ID 静默验证。

此外,如果提交未通过验证,切勿向用户透露原因 - 这样作弊者就不会知道您是如何跟踪他们的。您还可以添加“5 个无效者,您出局”跟踪,但您需要为此登录。

【讨论】:

【参考方案4】:

使用会话 ID 无疑是一种方法。但是还有其他选项,其中大部分(如果不是全部)涉及添加一些数据作为隐藏字段。

    使用验证码。这对于每个页面加载始终是唯一的,因此必须使用您的表单。 生成随机数据并将其存储在数据库中(或只是$_SESSION 变量)并在提交表单后检查它。

选项一是我推荐的用户创建表单,因为它具有双重职责。它会停止自动提交您自己的表单,同时确保 $_POST 数据来自您自己的表单。

【讨论】:

【参考方案5】:

这是防止 XSRF 的标准模式模式。本质上它与您提到的类似。当为用户呈现表单时,服务器会创建一个随机令牌。它与用户的浏览器 cookie 相关联。在表单提交时,它会被发送回服务器。然后服务器将令牌与发出的令牌进行比较,只有在成功匹配后才会执行表单操作。

【讨论】:

【参考方案6】:

在表单中放置一个唯一值并与服务器端会话中存储的值相匹配,有很多很好的提及。这样做,但也要考虑当用户使用后退按钮并可能尝试提交表单两次,或者他们打开第二个浏览器窗口(同一个会话!),或者他们在您的网站上使用多个表单时会发生什么。

不要因为没有仔细考虑您的系统而造成疯狂的错误。

【讨论】:

感谢您的帮助,我没有想到此操作可能产生的其他影响。虽然我认为这些问题可以使用if(!isset($_SESSION['hash']))create hashelseuse existing hash 之类的东西来避免。

以上是关于php 你如何确保 $_POST 数据来自你的表单而不是外部影响?的主要内容,如果未能解决你的问题,请参考以下文章

php表单提交时获取不到post数据的解决方法

PHP表单-PHP $_POST 变量

PHP 使用表单提交到本页,POST接收不到数据值

PHP 使用 new FormData() 和 append() 处理来自 XMLHttpRequest2 的 $_POST

php函数里面怎么获取post过来的值

如何在php网页中通过一个表单让使用者输入数据提交后把输入的数据传递到mysql数据库中?