簡體   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