PHP Session与AJAX冲突

时间:2011-01-25 02:41:48

标签: php mysql security session csrf

代码说千言万语

page.php文件?ID = 123

<?php
if(is_ajax()){// function that determines whether the request is from ajax (http header stuff)
$_SESSION['token'] = md5(rand());
}
//some ajax request to ajax.php?id=123
?>

ajax.php?ID = 123

<?php
if($_SESSION['token'] == $_GET['token']){
echo 'Tell me this is for reall';
}else{
echo 'Invalid Request';
}
?>

在用户在另一个标签页上打开 page.php?id = 456 之前,每件事情都可以正常工作,ajax会在 page.php上返回'无效请求'?id = 123 如何解决这个冲突?

ps:如果可能的话,我希望每个页面的新会话用于CSRF目的

3 个答案:

答案 0 :(得分:4)

如果我理解正确,听起来就像是为每个请求设置了令牌。我的猜测是旧页面仍有旧令牌。我会检查是否在自动吹走之前设置了令牌。

 if (isset($_SESSION['token'])){
    //do nothing
 } else{
   $_SESSION['token'] = md5(rand());
 }

修改以解决您的问题。

不是仅使用“令牌”的一个键,而是为每个浏览器会话创建一个键。

$_SESSION[$sessionId] = md5(rand());

诀窍当然是找出发生的时间,因为如果你不能使用会话,你真的不知道请求是来自新标签还是旧标签。您可以使用查询字符串来传递此参数。基本上所有请求都必须具有此参数,否则您不会将会话与它们关联。

e.g。

http://www.yoursite.com/somepage.php?sessionid=<some generated id>

最终,用户可能会对此表示不满,但我不确定是否有任何解决方法。

编辑2 好的,这是我对如何做到这一点的想法。安全专家在那里,如果我有这个错误,请随意给我发火焰,就像我之前说的那样,我不是专家,但看起来我不会在没有暗示的情况下摆脱这种情况; - )

CSFR的问题是,某些恶意用户Bob可能会在另一个网站上创建一个元素,导致Alice的浏览器向其他网站发出请求,因为Alice之前已登录并且该信息存储为通过会话识别cookie或Alice,该站点执行请求,就好像Alice已经请求它一样。例如,如果Alice的银行是http://www.mybank.com,那么Bob可以创建一个包含

的论坛帖子
<img srg="http://www.mybank.com/transferfunds.php?amount=1000&receiver=Bob" />

爱丽丝的银行会认出她的浏览器提出请求,认为这是她的。有一些关键的事情必须发生(一起,这些失败中的任何一个会导致攻击失败)使这成为可行的攻击(这些是理解如何防止它的关键):

  1. Alice必须登录她的银行网站,以便银行记住她。这可能发生在cookie(“记住我”)或通过会话。但是,如果她关闭浏览器(结束会话)或清除她的cookie,就没有威胁,因为银行网站不会识别她并拒绝该请求。
  2. Bob必须能够为请求提供所有必要的参数,否则银行网站将拒绝该请求。
  3. 为了在无状态协议(HTTP)之上提供一些“状态”概念,你实际上无法绕过(1)中的风险。除非你让人们总是点击“注销”或关闭他们的窗口等,否则你无法在浏览器或会话中存储信息。但是,您可以防止(2)成为问题。我对此的解决方案(我确信还有很多其他的)是生成一个哈希值,就像你正在做的那样并将它存储在会话中。

    例如,

    $_SESSION['token'] = md5(rand());
    

    然后,您所做的就是将该令牌附加到所有内部链接。

    http://www.mysite.com/secure.php?token=giuwnrefviunslfghahgliuwnvwrgbaasd

    从不将该令牌存储在浏览器内存中:即cookie。提出请求时,在执行任何操作之前,请检查令牌

    //note, you'll want to sanitize user input, I'm just being brief
    if ($_GET['token'] != $_SESSION['token']){
       //User either attempted to enter a link on their own or it's a CSRF attack
       header('HTTP/1.1 403 Forbidden');
     }else{
     //do whatever needs to be done
     }
    

    关键是您网站上的所有链接都包含令牌。但是,Bob无法知道该令牌是什么,因为它没有存储在浏览器的cookie中。如果他试图创建一个链接到您的某个页面,它将包含错误的密钥,或者它不包含任何密钥,您可以拒绝它。 (公平地说,他有可能正确猜出碰巧看到他的代码的特定用户的令牌,但他可能更容易爆发火焰。)

    没有必要为令牌分配超时,因为当浏览器关闭时令牌将被删除,并且当用户访问站点时需要重新生成令牌。

答案 1 :(得分:1)

你想做什么?我们能看到JavaScript吗?

看起来您将会话令牌设置为随机哈希,然后再进行检查。因此,如果用户打开两次页面,它将再次随机化并使前一个令牌无效。你期待什么行为?

答案 2 :(得分:0)

您需要让每个页面都启动它自己的令牌,否则会发生这种冲突。

<?php
if(is_ajax()){// function that determines whether the request is from ajax (http header stuff)
$page_id = $_GET['id'];
$_SESSION['token'][$page_id] = md5(rand());
}
//some ajax request to ajax.php?id=123
?>

<?php
$page_id = $_GET['id'];
if($_SESSION['token'][$page_id] == $_GET['token']){
echo 'This is for real!';
}else{
echo 'Invalid Request';
}
?>

根据您如何实现所有内容,您可能需要更复杂或更专业的内容,但这应该可以帮助您入门。