PHP会话与AJAX冲突 [英] PHP Session conflicts with AJAX

查看:190
本文介绍了PHP会话与AJAX冲突的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

代码讲出一千个单词



page.php?id = 123

 <?php 
if(is_ajax()){//确定请求是否来自ajax(http标头的东西)的函数
$ _SESSION ['token'] = md5(rand ());
}
//一些对ajax.php的ajax请求?id = 123
吗?

ajax.php?id = 123

 <?php 
if($ _ SESSION ['token'] == $ _GET ['token']){
echo'告诉我这是真实的';
} else {
echo'Invalid Request';
}
?>

在用户打开 page.php?id = 456 在另一个标签上,ajax在 page.php?id = 123 上返回无效请求。



ps:如果可能的话,我想为CSRF的目的为每个页面设置新会话

解决方案

如果我正确理解这一点,听起来你在为每个请求设置令牌。我的猜测是旧页面仍具有旧令牌。在自动删除令牌之前,我会先检查令牌是否已设置。

  if(isset($ _ SESSION ['token' ])){
//不执行任何操作
} else {
$ _SESSION ['token'] = md5(rand());
}

编辑以解决您的问题。



不仅仅是为每个浏览器会话创建一个密钥,而不仅仅是使用一个令牌密钥。

  $ _ SESSION [$ sessionId] = md5(rand()); 

技巧当然是弄清楚什么时候发生,因为如果您不能使用会话,您真的不知道该请求是来自新标签还是旧标签。您可以使用查询字符串来传递此参数。基本上,所有请求都必须具有此参数,否则您不会将会话与其关联。



例如

  http://www.yoursite.com/ somepage.php?sessionid =<某些生成的ID> 

最终,用户可能会对此感到厌烦,但我不确定是否有解决办法。 / p>

编辑2 好的,这是我对如何执行此操作的想法。安全专家在那里,如果我有这个错误,请随时开除我,就像我在没有专家之前所说的那样,但是看起来我不会在不提出任何建议的情况下摆脱困境;-)



CSFR的问题是,某些恶意用户Bob可以在另一个站点上创建一个元素,从而导致Alice的浏览器向其他站点发出请求,并且,因为Alice以前有登录并通过会话识别信息存储为cookie或Alice时,站点将执行该请求,就像Alice曾请求过一样。例如,如果爱丽丝的银行是 http://www.mybank.com ,那么鲍勃可以创建一个论坛帖子,包含

 < img srg = http://www.mybank.com/transferfunds.php?amount=1000&receiver =鲍勃 /> 

Alice的银行会认为她是浏览器,因此认为她是浏览器。要使此攻击成为可行的攻击,必须要完成一些关键的事情(这些失败中的任何一个都会导致攻击失败):


  1. 爱丽丝必须登录她的银行站点,以便银行记住她。这可以在Cookie(记住我)中或通过会话进行。但是,如果她关闭浏览器(结束会话)或清除cookie,则不会受到威胁,因为银行站点不会识别她并将拒绝该请求。

  2. Bob必须是能够为请求提供所有必要的参数,否则银行网站将拒绝该请求。

基于无状态协议(HTTP)的状态,您真的无法避免(1)中的风险。除非让人们总是单击注销或关闭其窗口等,否则您将无法在浏览器或会话中存储信息。但是,可以防止出现问题(2)。我对此的解决方案(我敢肯定还有很多其他解决方案)是生成哈希,就像您正在做的那样,并将其存储在会话中。



例如,

  $ _ SESSION ['token'] = md5(rand()); 

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



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



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

  // note,您需要对用户输入进行清理,我只是简短地
if($ _GET ['token']!= $ _SESSION ['token']){
//用户要么尝试自行输入链接,要么是CSRF攻击
标头('HTTP / 1.1 403 Forbidden');
} else {
//做任何需要做的事情
}

关键是您网站上的所有链接都将包含令牌。但是,鲍勃无法知道该令牌是什么,因为它没有存储在浏览器的Cookie中。如果他尝试制作指向您的页面的链接,则该链接要么包含错误的密钥,要么将不包含任何密钥,您可以拒绝它。 (为公平起见,他有机会正确地猜测碰巧正在查看其代码的特定用户的令牌,但他可能更容易起火。)



无需为令牌分配超时,因为令牌将在关闭浏览器时消失,而在用户访问站点时需要重新生成。


code speaks a thousand words

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';
}
?>

Every thing works fine until the user opens page.php?id=456 on another tab, the ajax returns 'invalid request' on page.php?id=123 How to resolve this conflict?

ps: if its possible i want new session for each page for CSRF purposes

解决方案

If I understand this correctly, it sounds like you're setting the token for each request. My guess would be that the old page still has the old token. I would check to see if the token is set before automatically blowing it away.

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

Edit To address your question.

Rather than just using one key of "token," create a key for each browser session.

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

The trick, of course will be figuring out when those happen because if you can't use session, you really won't know whether the request is coming from a new tab or an old one. You could the use the query string to pass this parameter around. Basically all requests would have to have this parameter otherwise you don't associate a session with them.

e.g.

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

Ultimately, the user could monkey with this but I'm not sure there's any way around that.

Edit 2 Ok, here's my thought for how you should do this. Security experts out there, feel free to flame me if I have this wrong, like I said before I'm no expert, but it doesn't look like I'm going to get out of this without suggesting something ;-)

The issue with CSFR is that some malicious user, Bob, could create an element on another site that causes Alice's browser to make a request to some other site and, because Alice had previously logged in and that information is stored either as a cookie or Alice is recognized via session, the site executes the request as if Alice had requested it. For instance, if Alice's bank is http://www.mybank.com, then Bob could create a forum post that contains

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

Alice's bank would recognize her browser as making the request, thinking it's her. There are a couple of key things that have to happen (together, either of these failing will cause the attack to fail) to make this a viable attack (these are the key ones to understanding how to prevent it):

  1. Alice has to have logged into her bank site such that the bank remembers her. This could happen either in a cookie ("remember me") or via session. However, if she closes her browser (ends the session) or clears her cookies, there's no threat because the bank site won't recognize her and will deny the request.
  2. Bob has to be able to supply all of the necessary parameters to the request, otherwise the bank website will deny the request.

In order to provide some notion of "state" on top of a stateless protocol (HTTP), you really can't get around the risk in (1). Unless you get people to always click "log out" or close their window etc, there's nothing you can do get around storing information in the browser or session. However, you can prevent (2) from being a problem. My solution to this (and I'm sure there are tons of others) is to generate a hash, like you're doing and store it in session.

For instance,

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

Then, what you do is append that token to all of your internal links.

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

You NEVER store that token in browser memory: i.e. a cookie. When requests are made, before you do anything, you check the token

//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
 }

The key to this is that all of the links on your site will include the token. However, Bob has no way of knowing what that token is because it's not stored in a cookie on the browser. If he attempts to craft a link to one of your pages, it will either contain the wrong key, or it won't contain any key and you can deny it. (To be fair, there is a chance he could correctly guess the token for a specific user that happens to view his code, but he's probably more likely to burst into flames.)

There's no need to assign a timeout to the token either as the token will be obliterated when the browser is closed and need to be regenerated when the user visits the site.

这篇关于PHP会话与AJAX冲突的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆