如何为检查请求源提供更多安全性

时间:2010-06-28 12:54:34

标签: php security csrf

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

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

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

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

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

有人有想法,请分享吗?

提前致谢

3 个答案:

答案 0 :(得分:7)

网络安全中的第1课: 永远不要相信用户输入。当我说永远不会,我的意思是永远不会。 ;)包含PHP中的HTTP_REFER var,它很容易受到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!");
   }
?>

答案 1 :(得分:3)

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

根据美国国土安全部的说法,我找到了most dangerous CSRF vulnerability ever found并且是有史以来最危险的1000个漏洞。摩托罗拉使用引用检查修补了这个漏洞,并且通常在嵌入式网络硬件上看到这种保护方法,因为内存很少。

更常见,更安全的方法是在$_SESSION变量中存储Cryptographic nonce,并针对每个敏感请求进行检查。一种简单的方法是对所有敏感请求(如更改密码)使用POST,并确保此加密随机数对php头文件中的所有帖子有效,如果它无效,则unset($_POST); 。此方法有效,因为虽然攻击者可以强制您的浏览器进入SENDING GET / POST请求,但他无法查看RESPONSE,并且无法读取伪造请求所需的此令牌。可以使用XSS获取此令牌,因此请确保test your site for xss

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

答案 2 :(得分:2)

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

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

针对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保护措施,因为攻击者随后可以控制用户会话,因此可以“预测”秘密令牌。

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