我正在从会话保护的页面执行标准的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在这种条件下工作?
编辑:所有文件都在同一个域中。
我们有index.php,其中包含js,我们有queries.php这是由ajax请求调用的php文件,我们有s_session.php,其中包含上面编写的构造函数。
文件index.html和queries.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是成功的。所有其他在用户之后完成并由用户触发的都是不成功的
答案 0 :(得分:2)
这主要是由竞争条件引起的,但也可能存在浏览器错误。
我将排除浏览器错误情况,但提供的信息存在冲突,更具体地说是this comment:
这是几个关于用户操作的调用,从不同时进行。
如果请求从未同时执行,那么这只会意味着您的浏览器无法正常运行,并且会发生下列情况之一:
Set-Cookie
标头(如果该逻辑取决于HttpOnly
标志,这可以解释为什么网络仍然有效:D)onLoad
事件实际上是在页面加载期间执行的(我知道这没有意义,但如果它是一个浏览器错误,一切都可能发生)当然,这些都不太可能发生,所以我倾向于说你实际上一次处理多个AJAX请求,在这种情况下竞争条件是合理的情况:
我个人会看看onLoad
事件触发的内容 - 将所有初始化逻辑放在那里很容易,并且忘记这可能包含多个异步请求。
无论哪种方式,你真正的逻辑错误都是这段代码:
if ( SESSION_REGENERATE_ID )
session_regenerate_id(SESSION_REGENERATE_ID);
您在两种不同条件下使用相同的值:
session_regenerate_id()
选项不确实会立即销毁这些数据,以便通过异步请求为这些竞争条件提供解决方案,因为它们实际上是不可避免的。竞争条件 会在某个时刻发生,无论你多么努力地避免它 - 即使没有逻辑缺陷,网络滞后(例如)仍可能触发它。 /> 保留旧会话的数据(暂时当然)通过简单地允许"迟到"来解决该问题。或"不同步"请求处理启动时可用的任何数据。
会话垃圾收集器稍后将清除过期的会话。这可能并不理想,但几乎是需要您删除数据的存储的唯一解决方案(与Redis等缓存存储相反,它允许您设置TTL值而不必手动删除)。
就个人而言,我更喜欢在AJAX请求期间避免会话ID重新生成...正如您所看到的,它是一种蠕虫病毒。 :)