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


php How do you ensure $_POST data is coming from your form and not a outside influence?

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

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

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

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

话虽如此,有些事情可以帮助您限制和验证正在提交的数据。首先,要求用户使用(会话(cookie登录。这消除了匿名用户的随机请求。其次,您可以将令牌作为隐藏字段嵌入到表单中,也可以将其保存到用户的会话中。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');
}

这只是一个简单的例子,您可能希望按字母顺序对键进行排序,以确保获得相同的哈希等。它演示了用户需要为每个请求都有一个唯一令牌的概念,尽管这可以防止使用表单和提交比所需更多或更少的数据。

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

$ref = $_SERVER['HTTP_REFERER'];
if($ref !== 'some site path/index.php')
{
    die("Access Denied!");
}

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

稍微

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

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

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

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

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

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

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

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

有很多

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

不要因为不考虑你的系统而制造疯狂的错误。