繁体   English   中英

getJSON和session_regenerate_id()

[英]getJSON and session_regenerate_id()

我正在从受会话保护的页面执行标准的getJSON查询:

$.getJSON('queries.php',{q: 'updateEvent', param1: p1},
    function(data){
        ...
    }
);

在我的会话构造函数上,我设置了以下内容:

function startSession() 
{
    ini_set('session.use_only_cookies', SESSION_USE_ONLY_COOKIES);

    $cookieParams = session_get_cookie_params();
    session_set_cookie_params(
        $cookieParams["lifetime"], 
        $cookieParams["path"], 
        $cookieParams["domain"], 
        SESSION_SECURE, 
        SESSION_HTTP_ONLY
     );

    session_start();

    if ( SESSION_REGENERATE_ID )
        session_regenerate_id(SESSION_REGENERATE_ID);   
}

如果我将SESSION_REGENERATE_ID设置为true,那么我的getJSON将发送一个令牌,但接收到另一个令牌,从而使请求失败。 因此,目前我正在将SESSION_REGENERATE_ID设置为false。

有没有办法让getJSON在这样的条件下工作?

编辑:所有文件都在同一个域下。

我们在其中包含js的index.php中,有在ajax请求调用的php文件中的querys.php,在其中包含上述构造函数的s_session.php中。

首先,文件index.html和query.php都受到保护:

include "s_session.php"; 
if(!$login->isLoggedIn()) {
  header('Content-Type: application/json'); 
  echo json_encode(array('content' => 'Login failed')); 
  exit;
}

PHPSESSID在set-cookie下的ajax请求的标头中。 答案中返回的PHPSESSID与session_regenerate_id所期望的不同。

如果将SESSION_REGENERATE_ID设置为FALSE,则请求将顺利进行。 如果将其设置为TRUE,则会收到错误消息“登录失败”。

这是isLoggedIn():

public function isLoggedIn() {
    //if $_SESSION['user_id'] is not set return false
    if(ASSession::get("user_id") == null)
         return false;

    //if enabled, check fingerprint
    if(LOGIN_FINGERPRINT == true) {
        $loginString  = $this->_generateLoginString();
        $currentString = ASSession::get("login_fingerprint");
        if($currentString != null && $currentString == $loginString)
            return true;
        else  {
            //destroy session, it is probably stolen by someone
            $this->logout();
            return false;
        }
    }

    $user = new ASUser(ASSession::get("user_id"));
    return $user->getInfo() !== null;
}

编辑2:这是完整的ASSession代码:

class ASSession {

/**
 * Start session.
 */
public static function startSession() 
{
    ini_set('session.use_only_cookies', SESSION_USE_ONLY_COOKIES);

    session_start();
    $s = $_SESSION;

    $cookieParams = session_get_cookie_params();

    session_set_cookie_params(
        $cookieParams["lifetime"], 
        $cookieParams["path"], 
        $cookieParams["domain"], 
        SESSION_SECURE, 
        SESSION_HTTP_ONLY
     );

    if ( SESSION_REGENERATE_ID )
        session_regenerate_id(SESSION_REGENERATE_ID);

    //$_SESSION = $s;

}

/**
 * Destroy session.
 */
public static function destroySession() {

    $_SESSION = array();

    $params = session_get_cookie_params();

    setcookie(  session_name(), 
                '', 
                time() - 42000, 
                $params["path"], 
                $params["domain"], 
                $params["secure"], 
                $params["httponly"]
            );

    session_destroy();
}

/**
 * Set session data.
 * @param mixed $key Key that will be used to store value.
 * @param mixed $value Value that will be stored.
 */
public static function set($key, $value) {
    $_SESSION[$key] = $value;
}

/**
 * Unset session data with provided key.
 * @param $key
 */
public static function destroy($key) {
    if ( isset($_SESSION[$key]) )
        unset($_SESSION[$key]);
}

/**
 * Get data from $_SESSION variable.
 * @param mixed $key Key used to get data from session.
 * @param mixed $default This will be returned if there is no record inside
 * session for given key.
 * @return mixed Session value for given key.
 */
public static function get($key, $default = null) {
    if(isset($_SESSION[$key]))
        return $_SESSION[$key];
    else
        return $default;
}

}

编辑3:这是请求标头和响应cookie:

在此处输入图片说明 在此处输入图片说明

我注意到在onload期间执行的第一个getJSON成功。 在用户触发之后执行的所有其他操作均未成功

这主要是由竞争条件引起的,但浏览器错误也可能会导致。

排除浏览器错误的情况,但是所提供的信息有冲突,更具体地讲,在此注释中

它是几次呼叫,是根据用户操作一个接一个地进行的,永远不会同时进行。

如果 从未同时执行这些请求,则仅意味着您的浏览器无法正常运行,并且发生以下情况之一:

  • 丢弃它在响应中收到的Set-Cookie标头(如果该逻辑取决于HttpOnly标志,这将说明为什么Web仍然可以工作:D)
  • 实际上, onLoad事件是在页面加载期间执行的(我知道这没有意义,但如果是浏览器错误,一切皆有可能)

当然,这些可能性极不可能发生,因此我倾向于说您实际上一次要处理多个AJAX请求,在这种情况下,竞争条件是一个合理的情况:

  1. 第一个请求开始(使用您的初始PHPSESSID)
  2. 第二个请求开始(再次,使用相同的PHPSESSID)
  3. 处理第一个请求并接收带有新PHPSESSID的响应
  4. 到目前为止,第二个请求已被阻止(会话处理程序使用锁定来防止多个进程同时修改同一数据),并且现在才开始使用初始PHPSESSID进行处理,该操作在此时是无效的,因此为什么触发注销。

我个人来看一下该onLoad事件触发了什么-将所有初始化逻辑放在其中很容易,而忘记了其中可能包含多个异步请求。


无论哪种方式,您真正的逻辑错误就是这段代码:

if ( SESSION_REGENERATE_ID )
    session_regenerate_id(SESSION_REGENERATE_ID);

您在两种不同的情况下使用相同的值:

  1. 确定是否完全重新生成会话ID
  2. 告诉session_regenerate_id()是否应立即销毁与旧会话ID相关联的数据

选择立即销毁该数据就可以为异步请求提供这些竞争条件的解决方案,因为实际上这是不可避免的。 无论您如何努力避免这种情况,竞赛条件都会在某个时刻发生-即使没有逻辑缺陷,网络延迟(例如)仍然可能触发它。
通过简单地允许“延迟”或“不同步”请求处理开始时可用的任何数据,保留旧会话的数据(当然是暂时的)可以解决该问题。

过期的会话将在以后由会话垃圾收集器清除。 这可能并不理想,但是几乎是需要删除数据的存储的唯一解决方案(与Redis这样的缓存存储相对,后者允许您设置TTL值而不必手动删除)。

就个人而言,我更喜欢避免在AJAX请求期间特别是会话ID的再生……正如您所看到的,它是蠕虫病毒。 :)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM