У меня проблема с некоторыми функциями сессии и тем, как Chrome выполняет предварительную выборку / рендеринг. Я пытаюсь связать часть программного обеспечения форума (esoTalk) с пользовательским приложением laravel 4.3. У меня есть прослушиватели событий аутентификации, которые заставляют laravel создавать сеанс php (в дополнение к встроенному сеансу laravel), который позволяет форуму и приложению обмениваться данными аутентификации. При доступе к форуму, и если пользователь не вошел в систему — но эта общая информация существует (то есть пользователь вошел в приложение laravel), форум войдет в систему этого пользователя, используя информацию, доступную в сеансе.
По большей части это работает хорошо, за исключением того, что предварительная выборка Chromes, похоже, ломает вещи. Если я наблюдаю за форумом с помощью отладчика, я вижу, что когда я набираю URL-адрес форума, но перед тем, как нажать, введите chrome, чтобы получить доступ к форуму. После завершения работы с отладчиком я вижу, что он делает все, что ему нужно, и успешно выполняет вход в систему. В качестве последнего шага форум повторно генерирует идентификатор сеанса, чтобы прекратить угон. Вот где это ломается. Похоже, что chrome игнорирует новый идентификатор сеанса (отправленный через заголовок http SetCookie), поэтому, когда я нажимаю Enter, я иду на форум (и делаю новый запрос), используя исходный идентификатор сеанса. Этот идентификатор не существует, поэтому я настроен на новый и, следовательно, теряю статус входа в систему. Для пользователя это выглядит так, будто они никогда не входили в систему.
Я гуглил все выше и ниже для предложений о том, как я могу обойти это. Я не хочу удалять регенерацию идентификатора сеанса, так как она служит цели безопасности. Я также не могу отключить предварительную выборку / рендеринг Chrome. В общем, я, кажется, немного соленая.
Я создал некоторый код, который повторяет это. Хотя это зависит от включения предварительного рендеринга (так что вам нужно будет нажимать каждый из файлов через адресную строку несколько раз)
// test1.php
<?php
function regenerateToken()
{
session_regenerate_id(true);
$_SESSION["token"] = substr(md5(uniqid(rand())), 0, 13);
$_SESSION["userAgent"] = md5($_SERVER["HTTP_USER_AGENT"]);
}
// Start a session.
session_set_cookie_params(0, '/');
session_name("SessionBork_Test_session");
session_start();
$_SESSION["SentryUserId"] = '99';
regenerateToken();
header('Content-Type: text/plain');
foreach ($_SESSION as $k => $v) {
echo $k . " = " . $v . "\n";
}
Получите доступ к test1.php, за которым следует test2.php, и вы должны увидеть кучу выходных данных переменной сеанса. Как только начнется рендеринг / выборка, вы начнете получать прерванное сообщение.
// test2.php
<?php
function regenerateToken()
{
session_regenerate_id(true);
$_SESSION["token"] = substr(md5(uniqid(rand())), 0, 13);
$_SESSION["userAgent"] = md5($_SERVER["HTTP_USER_AGENT"]);
}
// Start a session.
session_set_cookie_params(0, '/');
session_name("SessionBork_Test_session");
session_start();
if (empty($_SESSION["token"])) regenerateToken();
// Complicate session highjacking - check the current user agent against the one that initiated the session.
if (md5($_SERVER["HTTP_USER_AGENT"]) != $_SESSION["userAgent"])
session_destroy();
// Log in a the user based on the SentryUserId
// ... logging in, setting userId, regenerating session
$_SESSION["userId"] = '10';
regenerateToken();
header('Content-Type: text/plain');
foreach ($_SESSION as $k => $v) {
echo $k . " = " . $v . "\n";
}
if ( ! isset($_SESSION['SentryUserId'])) echo "\n--\nPrerendering brokeded me.";
Если вы можете подключить его к xdebug в IDE или к чему-то еще, вы должны увидеть скрытый удар prerender для test2.php (который выглядит абсолютно правильным в ответе), а затем последующий фактический удар, когда вы нажмете Enter, где он забыл, кто ты.
Одним из способов решения этой проблемы было бы обнаружение предварительных выборок, а не генерация нового идентификатора сеанса при этих нагрузках. Посмотрите это Переполнение стека для информации об обнаружении предварительной выборки в различных браузерах: HTTP-заголовок для обнаружения запроса предварительной загрузки от Google Chrome
Кроме того, я бы сказал, что существуют более эффективные способы предотвращения перехвата сеансов (например, привязка сеанса к IP-адресу, подписи браузера и т. Д.)
Кроме того, в вашем коде может быть вторая ошибка: вызов session_destroy()
уничтожает сеанс И закрывает сеанс пользователя. Вам нужно позвонить session_start()
до звонка session_regenerate_id()
, Смотри документацию Вот и примеры Вот.
Других решений пока нет …