【问题标题】:How do I provide more security for checking source of the request如何为检查请求的来源提供更多安全性
【发布时间】:2011-03-09 03:09:23
【问题描述】:

我正在开发一个 PHP Web 应用程序,我想为应用程序提供更高的安全性,以便没有人可以轻易破坏该功能。

关于我的问题的简要说明: 在一个模块中,有一个阶段我正在检查请求的来源(该请求的来源)

目前,我正在使用HTTP_REFERRER 变量(在 php 中可用)。我正在使用一个特定的 URL(例如 http://www.example.com/test.php )检查这个变量值。如果存在完全匹配,那么只有我在调用进一步的操作。

我对上述方法有点困惑,我应该使用 HTTP_REFERRER 还是检查 IP 地址(如果请求来自任何特定 IP 地址,则有效请求)?

我还想知道提供安全性的更好方法。

有人有想法吗,请分享一下?

提前致谢

【问题讨论】:

  • HTTP_REFERER 与请求源无关。你最好检查一个 IP 地址

标签: php security csrf


【解决方案1】:

网络安全第一课: 永远不要相信用户输入。当我说从不时,我的意思是从不。 ;) 包括 PHP 中的 HTTP_REFER 变量,它很容易被 http 标头破坏(来源:http://www.mustap.com/phpzone_post_62_how-to-bypass-the-referer-se

检查来源的一种可能解决方案是使用表单令牌(csrf 保护):http://www.thespanner.co.uk/2007/04/12/one-time-form-tokens/,但也不是那么安全,只能使用您自己的来源。

一个简单的CSRF(跨站请求伪造)保护示例:(因此简单。对于更安全/稳健的解决方案,请参阅The Rook的答案)

1) 在您的表单页面中,创建某种令牌并将其放入您的会话和隐藏的表单字段中:

<?php
    session_start();
    $csrfToken = md5(uniqid(mt_rand(),true)); // Token generation updated, as suggested by The Rook. Thanks!

    $_SESSION['csrfToken'] = $token;
?>
<form action="formHandler.php">
   <input type="hidden" name="csrfKey" value="<?php echo $csrfToken ?>" />
</form>

2) 在您的表单处理程序中检查令牌是否有效。

<?php
   session_start();
   if($_POST['csrfKey'] != $_SESSION['csrfKey']) {
      die("Unauthorized source!");
   }
?>

【讨论】:

  • 感谢大家的快速回复,@Treur:我的有效测试案例是:我正在使用简单的表单方法发布一些值,例如 'age' 、 'id' 、 'description' 、 'remarks' .我将其发布到一个特定的 URL,该 URL 实际上是在这些值上进行的,这些值应该受到保护。所以在这里我想检查请求的来源是否有效。 ?
  • 在这种情况下,您想使用某种 csrf 保护。我用一个简单的例子更新了我的答案
  • -1 引用对于 csrf 保护是安全的,而您的 csrf 令牌生成非常不安全,这样更好:uniqid(mt_rand(),true); 攻击者会知道时间,毕竟他可以控制何时请求已发送。
  • 他是否知道时间并不重要,因为它与“秘密”盐结合在一起。我确实故意把它称为一个简单的例子;)
  • 我知道这是旧的,但第二个代码 sn-p 有错字。应该是$_SESSION['csrfToken']
【解决方案2】:

检查HTTP_REFERRER 的 CSRF 是一种有效的保护形式。虽然在你的OWN BROWSER 上欺骗这个 HTTP 标头是微不足道的,但在使用 CSRF 的其他人浏览器上欺骗它是不可能的,因为它是breaks the rules

根据国土安全部的说法,我发现了 most dangerous CSRF vulnerability ever found 并且是有史以来最危险的 1000 个漏洞之一。摩托罗拉使用引用检查修补了这个漏洞,由于内存稀缺,这种保护方法在嵌入式网络硬件上很常见。

更常见和更安全的方法是将Cryptographic nonce 存储在$_SESSION 变量中,并检查每个敏感请求。一种简单的方法是对所有敏感请求(例如更改密码)使用POST,并确保此加密随机数对php 头文件中的所有帖子都有效,如果无效则unset($_POST);。此方法有效,因为尽管攻击者可以强制您的浏览器发送 GET/POST 请求,但他无法查看响应,因此无法读取伪造请求所需的令牌。这个令牌可以通过 XSS 获得,所以请确保你test your site for xss

生成 csrf 令牌的好方法是 md5(uniqid(mt_rand(),true)); 这应该足够熵来阻止 CSRF。 md5() 用于隐藏盐的生成方式。请记住,当前时间不是秘密,攻击者确切地知道生成 CSRF 请求的时间,并且可以缩小会话的创建时间。您必须假设攻击者可以进行 许多 猜测,实际上这很容易通过向页面写入一堆 iframe 来完成。

【讨论】:

  • 抱歉,但是使用引用标头不是有效的 CSRF 保护。 referrer 标头是可选的,浏览器可以随时省略它(rfc2616,HTTP 1.1),并且可以进行欺骗。
  • 哦,使用会话变量也不安全。考虑以下情况:当用户使用表单进入页面时,您创建秘密令牌并将其设置为会话变量,当用户提交表单时,脚本检查令牌,如果有效,则执行操作.这可以简单地通过使用 iframe 和一些 javascript 来攻击。攻击者可以诱骗用户访问恶意站点。恶意站点包含一个 iframe,它加载目标站点的表单(现在设置了令牌)。攻击者使用 javascript 计时器更改 iframe 的源(继续)
  • (继续上一条评论)到目标 CSRF url。请求 URL 并设置会话变量,从而处理操作。
  • @Kim L 那么你写了多少 CSRF 漏洞利用?我已经写了很多,这就是为什么我知道您所描述的内容明显违反了同源政策。您需要阅读 Google 浏览器安全手册,然后尝试此攻击。 (它永远不会工作:)
  • @Kim L 另一件事,摩托罗拉冲浪板电缆调制解调器非常受欢迎,您可能在家中使用。转到192.168.100.1 并尝试编写一个 CSRF 漏洞来重新启动调制解调器。
【解决方案3】:

Treur 说得对,但我仍然想澄清一些事情,并为您提供一些参考资料来源。正如 Treur 所说,永远不要相信用户输入数据,其中包括浏览器发送的所有标头。

您所描述的是典型的跨站点请求伪造攻击。检查引荐来源头不是针对 CSRF 攻击的有效保护,因为根据 RFC2616 (Hyper Text Transfer Protocol 1.1),引荐来源标头是可选的,因此浏览器可以随时省略。如果您使用的是 SSL,那么浏览器始终会忽略引用标头。其次,它是用户定义的值,因此不应该被信任。

针对 CSRF 攻击的推荐保护措施是使用同步令牌模式。这意味着您应该创建一个秘密令牌,该令牌作为隐藏字段嵌入到您的表单中。发布表单时,您验证秘密令牌是否存在并且它是有效的。创建安全令牌有多种策略。我将描述一种创建令牌的方法:

为应用程序中的每个操作创建一个唯一的操作名称。例如,“delete_user”、“add_user”或“save_user_profile”。假设您描述的表单具有操作名称“foobar”。将操作名称与用户的会话 ID 和秘密值连接起来。

$stringValue = "foobar" . "secret value" . session_id();

要创建安全令牌,请创建连接字符串的哈希,您可以使用 sha1 创建哈希。要降低暴力攻击的风险,请在散列中使用较大的密钥,例如 sha 512。

$secretToken = hash("sha5125", $stringValue);

在表单的隐藏字段中设置此标记。提交表单后,重新创建令牌并验证它是否与表单中提交的令牌匹配。此令牌对一个用户会话有效。有人可能会争辩说,有一个机会之窗,攻击者可以重用令牌,因为它不是在每次请求时都重新生成的。但是,通过适当的会话管理策略,这不应该是一个真正的问题。

就像我说的,适当的会话管理是必要的。这意味着您不应该让会话保持很长时间。尤其是session fixation 漏洞将撤消任何 CSRF 保护措施,因为攻击者随后控制了用户会话,因此可以“预测”秘密令牌。

我建议您阅读以下几个链接:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-04
    • 2021-11-17
    • 2013-04-15
    • 2018-06-17
    相关资源
    最近更新 更多