【问题标题】:Data from the exact form来自确切表格的数据
【发布时间】:2012-05-06 10:39:40
【问题描述】:

我一直在谷歌上搜索,但我仍然没有答案,所以我决定在这里问这个问题: PHP中有没有办法检查我在某些脚本中收到的数据是否来自页面上的特定表单?我问是因为每个人都可以看到我用于将数据保存到我的数据库的脚本的名称,所以如果有人能够找出整个 URL,他也能够向脚本发送一些假数据,我需要一个条件,即只有当数据来自我页面上的正确表单时才会触发保存过程。

我使用jQuery调用AJAX函数,所以基本上如果我点击“发送”按钮,就会触发$.POST()方法来调用脚本来保存数据。

谢谢, 托马斯

【问题讨论】:

  • 恶意用户始终可以使用 Firebug 或 Fiddler 修改受信任的表单或请求数据本身。您在这里有什么顾虑?
  • @DCoder 如果使用恶意用户仍然需要从服务器获取安全令牌的令牌。如果需要某种登录过程来获取令牌(甚至是透明的公共无密码会话登录),那么您所描述的邪恶如果不先经过登录过程就无法使用萤火虫或类似的东西。当然,仍然可以对发送的请求进行操作。

标签: php jquery ajax forms


【解决方案1】:

使用令牌检查请求是否有效

您总是可以在提交数据时添加某种安全令牌:

在检查某些请求是否有效时,令牌可以很容易地扩展到许多不同的用途,并且覆盖范围很广,例如,您可以让您的非关键表单向公众开放,要求用户从某个页面获取他们的密钥(强制他们打开该页面),然后在提交数据时使用这些键来识别他们。

当然,所有这些都可以对用户完全透明,因为您可以通过 cookie(或会话 cookie,在此处无关紧要,没有更多或更少的安全性,因为服务器密钥在使用后应该更改)并在指定时间内或用户身份发生变化时失效)。
在此使用示例中,只有打开首页的用户才能向服务器提交数据。

另一种情况是 cookie 在包含用于向服务器提交数据的表单的同一页面上分发。每个打开页面的用户都会有他们的密钥来立即提交数据,但是如果有人试图从外部发出请求,它将失败。
OWASP Cross Site Request Forgery
codinghorror.com Blog CSRF and You

仅使用 AJAX?

这是我对另一个问题的回答,这个回答涵盖了向 ajax 请求插入附加数据的不同方法:Liftweb: create a form that can be submitted both traditionally and with AJAX(仔细查看

$.ajax({ 
    ... 
    data: /* here */ 
    ...

目前我以这种方式使用令牌:

用于提交的表单

这个隐藏的输入可以添加到表单中,这不是必需的,因为您可以使用前面描述的方法at another answer

<input type="hidden" name="formid" value="<?php echo generateFormId(); ?>" />

函数 generateFormId()

只需生成随机字符串并将其保存到会话存储中

function generateFormId() {
    // Insert some random string: base64_encode is not really needed here
    $_SESSION['FORM_ID'] = 'FormID'.base64_encode( uniqid() );
    // If you want longer random string mixed with some other method just add them:
    //$_SESSION['FORM_ID'] = 'FormID'.base64_encode( crypt(uniqid()).uniqid('',true) );
    return $_SESSION['FORM_ID'];
}

处理提交的表单数据

if (!isset($_SESSION['FORM_ID']) || $_SESSION['FORM_ID'] != $_POST['formid']) {
    // You can use these if you want to redirect user back to form, preserving values:
    //$_SESSION['RELOAD_POST'] = $_POST;
    //$_SESSION['RELOAD_ID'] = uniqid('re');
    echo 'Form expired, cannot submit values.';
    //echo '<a href="form.php?reload='.$_SESSION['RELOAD_ID'].'">Go back and try again</a>';
    exit(1); // <== Stop processing in case of error.
}

如果需要查看哪个表单提交数据

然后您可以在生成 id 时添加前缀,并在处理表单数据时检查该前缀。

当一个 php 脚本处理许多不同的表单时,就会出现这种情况。


请记住,防止恶意用户的唯一最终解决方案是是从您的服务器上拔下所有电线...

【讨论】:

  • 感谢您的回答。我喜欢你的令牌技术,这可能是我要使用的东西:-)
【解决方案2】:

这是一个有趣的话题,但您忽略了一个重点:垃圾邮件机器人/不良用户也可能通过使用该特定表单页面 (!) 来轰炸您的数据库。

因此,问题不是如何检查请求是否来自该页面,而是如何检查他是普通用户还是机器人/垃圾邮件发送者/机器人。

使用验证码,例如 http://www.recaptcha.net

如果我稍微误解了这个问题:如果您想确保请求来自“真实”用户,您将必须使用登录系统/用户系统并检查用户 ID/密码(通过 db 或会话)每次您想要执行数据库请求时。

【讨论】:

  • 感谢您的回答。好吧,我使用了很多正则表达式,我最喜欢的技术是每次有任何变化时检查字段中的值。如果它与该字段的 preg_match 匹配,我只需将值返回到该字段中,如果有一些问题,我总是返回原始值,其中没有坏字符。我认为多亏了这一点,没有办法通过表格发送一些讨厌的东西。你怎么看?顺便提一句。我真的不是验证码的粉丝,因为我只是觉得它对用户来说很烦人。
【解决方案3】:

您可以通过检查来验证页面是否通过 AJAX 被请求:

strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest'

您也可以查看HTTP_REFERER

但听起来您正在尝试保护处理易受攻击数据的页面。这需要的不仅仅是上述两件事。我建议在谷歌上搜索“CSRF Forgery”以获取更多信息。

【讨论】:

  • 感谢您的回答。听起来不错。我试图获取发送请求的页面的名称,但它不能正常工作,所以我放弃了。正如你所说,我会用谷歌搜索“CSRF Forgery”,因为你不是第一个向我推荐的人。谢谢。
【解决方案4】:

这些是你应该看看的东西。

  1. Capthcas.
  2. 推荐人检查。
  3. 使用 POST 而不是 GET。 [Curl 仍然可以自动化它。]

【讨论】:

  • 我不是 chaptcha 的忠实粉丝,因为我认为它只是让用户感到厌烦。顺便提一句。正如您在我的问题中看到的那样,我正在使用 POST。无论如何,谢谢你的回答:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-20
  • 2020-09-21
相关资源
最近更新 更多