Я не знаю наверняка, связана ли эта проблема с использованием Redis для сеансов, но это кажется правдоподобным. Эта проблема возникает только в больших масштабах с производственным трафиком и возникает примерно в 1–2% запросов на вход в систему.
После обновления до laravel 11 и переключения наших сеансов на хранение в Redis (AWS Elasticache Serverless ), мы часто получаем сообщения об ошибках 419 при попытке пользователей войти в систему. 419 означает, что токен CSRF не соответствует тому, что хранится в сеансе.
Похоже, что в этом коммите метод регенерации был изменен, чтобы начать восстановление токена CSRF в сеансе при входе в систему. Ранее вызывался только ->migrate(), который не должен генерировать новый токен CSRF.
Признак AuthenticatesUsers sendLoginResponse вызывает этот метод восстановления.
Я добавлено ведение журнала в структуру laravel, чтобы попытаться отладить проблему, код, который я изменил, приведен ниже. Судя по журналам, токен CSRF генерируется при загрузке страницы входа в систему, а затем восстанавливается, когда они отправляют запрос POST для входа в систему. Затем он сравнивает токен CSRF, отправленный с токеном, только что созданным с помощью запроса, что приводит к несоответствию.
В примере ниже:
16:42:08: Пользователь попадает на страницу входа, и запускается сеанс, который генерирует токен CSRF для сеанса, который передается странице.
16:42:13: пользователь отправляет сообщения на маршрут входа в систему, вызывается метод regenerate и генерируется новый токен CSRF. Затем можно увидеть, что сравнение CSRF не удалось, поскольку он считает, что действительным токеном CSRF является тот, который был только что сгенерирован в 16:42:13, а не токен CSRF, который был сгенерирован в 16:42:08.
* * - - [31/Dec/2024:16:42:08 +0000] "GET /admin/login HTTP/1.1" 200 30400 "https://*/admin/grid/day/2024-12-29" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Safari/605.1.15"
[2024-12-31 16:42:08] .INFO: SESSION DEBUG: start: regenerateToken {"session_id":"GKkRGO4gXaHgv97SNAGwU4IBh528n6aQ3lXNMux6","csrf_token":"fzpmkW7zrN3vVIcZHwag2f4VrqZeqXwPV01Wslv8","ip_address":"*","session_cookie":null}
[2024-12-31 16:42:12] .INFO: SESSION DEBUG: regenerate: regenerateToken {"session_id":"V1tl039u7Zko2FNKnYBmnktpkpjWvYWnbinQ7p10","csrf_token":"uMGctIR0qgYT50LJSM5VRjvMeN6nRU5ZwP143uF2","ip_address":"*","session_cookie":"GKkRGO4gXaHgv97SNAGwU4IBh528n6aQ3lXNMux6"}
* * - - [31/Dec/2024:16:42:13 +0000] "POST /admin/login HTTP/1.1" 419 67720 "https://*/admin/login" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Safari/605.1.15"
[2024-12-31 16:42:13] .INFO: SESSION DEBUG: Session ID: V1tl039u7Zko2FNKnYBmnktpkpjWvYWnbinQ7p10 Hash does not match: uMGctIR0qgYT50LJSM5VRjvMeN6nRU5ZwP143uF2 vs fzpmkW7zrN3vVIcZHwag2f4VrqZeqXwPV01Wslv8
Чтобы попытаться исправить это, я перезаписал sendLoginResponse, чтобы вызывать ->migrate() вместо ->regenerate(), который должен был восстановить предыдущее поведение laravel, когда новый Токен CSRF не генерируется при входе в систему. Проблема с этим изменением все еще наблюдается. В этом случае, как ни странно, кажется, что _token не установлен в сеансе, хотя он явно был установлен всего несколько секунд назад. См. примечание ниже: «Для запуска приведенного ниже кода не требуется устанавливать токен».
Пользователь, который попытался войти в систему ниже, является сотрудником, и я подтвердил, что он файлы cookie не были отключены, что в любом случае можно увидеть, поскольку файл cookie сеанса во втором запросе совпадает с файлом cookie первого.
16:03:43:< /strong> Пользователь загружает сайт, который генерирует сеанс.
16:03:47: Пользователь пытается войти в систему, и в этом запросе запускается новый сеанс/генерируется токен CSRF. Система считает, что это действительный токен CSRF сеанса, и сравнивает его с токеном CSRF в 16:03:43, что приводит к несоответствию.
* * - - [07/Jan/2025:16:03:43 +0000] "GET / HTTP/1.1" 200 26101 "https://*/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
[2025-01-07 16:03:43] .INFO: SESSION DEBUG: start: regenerateToken {"session_id":"SSJBXTCoydtRHdDhBBH224SQBYqM5PvrGMiCRzx1","csrf_token":"jhZ6BZ2Vo5212jo4EJo6qEkF1wqHjwDHAT2zVh19","ip_address":"*","session_cookie":"SSJBXTCoydtRHdDhBBH224SQBYqM5PvrGMiCRzx1"}
* * - - [07/Jan/2025:16:03:44 +0000] "GET /login HTTP/1.1" 200 23666 "https://*/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
[2025-01-07 16:03:47] .INFO: SESSION DEBUG: start: regenerateToken {"session_id":"SSJBXTCoydtRHdDhBBH224SQBYqM5PvrGMiCRzx1","csrf_token":"zvn0N1iXxY0eIvC1u6QGbQC1h3XSmxac027GVQBp","ip_address":"*","session_cookie":"SSJBXTCoydtRHdDhBBH224SQBYqM5PvrGMiCRzx1"}
[2025-01-07 16:03:47] .INFO: SESSION DEBUG: Session ID: SSJBXTCoydtRHdDhBBH224SQBYqM5PvrGMiCRzx1 Hash does not match: zvn0N1iXxY0eIvC1u6QGbQC1h3XSmxac027GVQBp vs jhZ6BZ2Vo5212jo4EJo6qEkF1wqHjwDHAT2zVh19
* * - - [07/Jan/2025:16:03:47 +0000] "POST /login HTTP/1.1" 419 67713 "https://*/login" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
Изменения кода для ведения журнала:
app/Http/Middleware/VerifyCsrfToken.php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
protected function tokensMatch($request)
{
$token = $this->getTokenFromRequest($request);
$is_session_token_string = is_string($request->session()->token());
$is_token_string = is_string($token);
$hash_equals = hash_equals($request->session()->token(), $token);
if (!$is_session_token_string) {
\Log::info('SESSION DEBUG: Session token stored in session is not a string: ' . $request->session()->token());
}
if (!$is_token_string) {
\Log::info('SESSION DEBUG: Token from request is not a string: ' . $token);
}
if (!$hash_equals) {
\Log::info('SESSION DEBUG: Session ID: ' . $request->session()->getId() . ' Hash does not match: ' . $request->session()->token() . ' vs ' . $token);
}
return $is_session_token_string && $is_token_string && $hash_equals;
}
}
Сессия/Store.php:
/**
* Generate a new session identifier.
*
* @param bool $destroy
* @return bool
*/
public function regenerate($destroy = false)
{
return tap($this->migrate($destroy), function () {
$this->regenerateToken();
$ipAddress = Request::header('CF-Connecting-IP', Request::ip());
$sessionId = $this->getId();
$sessionCookieName = config('session.cookie'); // Get session cookie name from config
$sessionCookieValue = Request::cookie($sessionCookieName);
Log::info("SESSION DEBUG: regenerate: regenerateToken", [
'session_id' => $sessionId,
'csrf_token' => $this->token(),
'ip_address' => $ipAddress,
'session_cookie' => $sessionCookieValue,
]);
});
}
/**
* Start the session, reading the data from a handler.
*
* @return bool
*/
public function start()
{
$this->loadSession();
if (! $this->has('_token')) { // regenerateToken();
$ipAddress = Request::header('CF-Connecting-IP', Request::ip());
$sessionId = $this->getId();
$sessionCookieName = config('session.cookie'); // Get session cookie name from config
$sessionCookieValue = Request::cookie($sessionCookieName);
Log::info("SESSION DEBUG: start: regenerateToken", [
'session_id' => $sessionId,
'csrf_token' => $this->token(),
'ip_address' => $ipAddress,
'session_cookie' => $sessionCookieValue,
]);
}
return $this->started = true;
}
Подробнее здесь: https://stackoverflow.com/questions/793 ... with-redis
Laravel 11 периодические ошибки 419 CSRF при входе в систему, сеансы, используемые с Redis ⇐ Php
Кемеровские программисты php общаются здесь
1736412886
Anonymous
Я не знаю наверняка, связана ли эта проблема с использованием Redis для сеансов, но это кажется правдоподобным. Эта проблема возникает только в больших масштабах с производственным трафиком и возникает примерно в 1–2% запросов на вход в систему.
После обновления до laravel 11 и переключения наших сеансов на хранение в Redis (AWS Elasticache Serverless ), мы часто получаем сообщения об ошибках 419 при попытке пользователей войти в систему. 419 означает, что токен CSRF не соответствует тому, что хранится в сеансе.
Похоже, что в этом коммите метод регенерации был изменен, чтобы начать восстановление токена CSRF в сеансе при входе в систему. Ранее вызывался только ->migrate(), который не должен генерировать новый токен CSRF.
Признак AuthenticatesUsers sendLoginResponse вызывает этот метод восстановления.
Я добавлено ведение журнала в структуру laravel, чтобы попытаться отладить проблему, код, который я изменил, приведен ниже. Судя по журналам, токен CSRF генерируется при загрузке страницы входа в систему, а затем восстанавливается, когда они отправляют запрос POST для входа в систему. Затем он сравнивает токен CSRF, отправленный с токеном, только что созданным с помощью запроса, что приводит к несоответствию.
[b]В примере ниже:[/b]
[b]16:42:08:[/b] Пользователь попадает на страницу входа, и запускается сеанс, который генерирует токен CSRF для сеанса, который передается странице.
[b]16:42:13[/b]: пользователь отправляет сообщения на маршрут входа в систему, вызывается метод regenerate и генерируется новый токен CSRF. Затем можно увидеть, что сравнение CSRF не удалось, поскольку он считает, что действительным токеном CSRF является тот, который был только что сгенерирован в 16:42:13, а не токен CSRF, который был сгенерирован в 16:42:08.
* * - - [31/Dec/2024:16:42:08 +0000] "GET /admin/login HTTP/1.1" 200 30400 "https://*/admin/grid/day/2024-12-29" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Safari/605.1.15"
[2024-12-31 16:42:08] .INFO: SESSION DEBUG: start: regenerateToken {"session_id":"GKkRGO4gXaHgv97SNAGwU4IBh528n6aQ3lXNMux6","csrf_token":"fzpmkW7zrN3vVIcZHwag2f4VrqZeqXwPV01Wslv8","ip_address":"*","session_cookie":null}
[2024-12-31 16:42:12] .INFO: SESSION DEBUG: regenerate: regenerateToken {"session_id":"V1tl039u7Zko2FNKnYBmnktpkpjWvYWnbinQ7p10","csrf_token":"uMGctIR0qgYT50LJSM5VRjvMeN6nRU5ZwP143uF2","ip_address":"*","session_cookie":"GKkRGO4gXaHgv97SNAGwU4IBh528n6aQ3lXNMux6"}
* * - - [31/Dec/2024:16:42:13 +0000] "POST /admin/login HTTP/1.1" 419 67720 "https://*/admin/login" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Safari/605.1.15"
[2024-12-31 16:42:13] .INFO: SESSION DEBUG: Session ID: V1tl039u7Zko2FNKnYBmnktpkpjWvYWnbinQ7p10 Hash does not match: uMGctIR0qgYT50LJSM5VRjvMeN6nRU5ZwP143uF2 vs fzpmkW7zrN3vVIcZHwag2f4VrqZeqXwPV01Wslv8
Чтобы попытаться исправить это, я перезаписал sendLoginResponse, чтобы вызывать ->migrate() вместо ->regenerate(), который должен был восстановить предыдущее поведение laravel, когда новый Токен CSRF не генерируется при входе в систему. Проблема с этим изменением все еще наблюдается. В этом случае, как ни странно, кажется, что _token не установлен в сеансе, хотя он явно был установлен всего несколько секунд назад. См. примечание ниже: «Для запуска приведенного ниже кода не требуется устанавливать токен».
Пользователь, который попытался войти в систему ниже, является сотрудником, и я подтвердил, что он файлы cookie не были отключены, что в любом случае можно увидеть, поскольку файл cookie сеанса во втором запросе совпадает с файлом cookie первого.
[b]16:03:43:< /strong> Пользователь загружает сайт, который генерирует сеанс.
16:03:47:[/b] Пользователь пытается войти в систему, и в этом запросе запускается новый сеанс/генерируется токен CSRF. Система считает, что это действительный токен CSRF сеанса, и сравнивает его с токеном CSRF в 16:03:43, что приводит к несоответствию.
* * - - [07/Jan/2025:16:03:43 +0000] "GET / HTTP/1.1" 200 26101 "https://*/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
[2025-01-07 16:03:43] .INFO: SESSION DEBUG: start: regenerateToken {"session_id":"SSJBXTCoydtRHdDhBBH224SQBYqM5PvrGMiCRzx1","csrf_token":"jhZ6BZ2Vo5212jo4EJo6qEkF1wqHjwDHAT2zVh19","ip_address":"*","session_cookie":"SSJBXTCoydtRHdDhBBH224SQBYqM5PvrGMiCRzx1"}
* * - - [07/Jan/2025:16:03:44 +0000] "GET /login HTTP/1.1" 200 23666 "https://*/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
[2025-01-07 16:03:47] .INFO: SESSION DEBUG: start: regenerateToken {"session_id":"SSJBXTCoydtRHdDhBBH224SQBYqM5PvrGMiCRzx1","csrf_token":"zvn0N1iXxY0eIvC1u6QGbQC1h3XSmxac027GVQBp","ip_address":"*","session_cookie":"SSJBXTCoydtRHdDhBBH224SQBYqM5PvrGMiCRzx1"}
[2025-01-07 16:03:47] .INFO: SESSION DEBUG: Session ID: SSJBXTCoydtRHdDhBBH224SQBYqM5PvrGMiCRzx1 Hash does not match: zvn0N1iXxY0eIvC1u6QGbQC1h3XSmxac027GVQBp vs jhZ6BZ2Vo5212jo4EJo6qEkF1wqHjwDHAT2zVh19
* * - - [07/Jan/2025:16:03:47 +0000] "POST /login HTTP/1.1" 419 67713 "https://*/login" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
[b]Изменения кода для ведения журнала:[/b]
app/Http/Middleware/VerifyCsrfToken.php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
protected function tokensMatch($request)
{
$token = $this->getTokenFromRequest($request);
$is_session_token_string = is_string($request->session()->token());
$is_token_string = is_string($token);
$hash_equals = hash_equals($request->session()->token(), $token);
if (!$is_session_token_string) {
\Log::info('SESSION DEBUG: Session token stored in session is not a string: ' . $request->session()->token());
}
if (!$is_token_string) {
\Log::info('SESSION DEBUG: Token from request is not a string: ' . $token);
}
if (!$hash_equals) {
\Log::info('SESSION DEBUG: Session ID: ' . $request->session()->getId() . ' Hash does not match: ' . $request->session()->token() . ' vs ' . $token);
}
return $is_session_token_string && $is_token_string && $hash_equals;
}
}
Сессия/Store.php:
/**
* Generate a new session identifier.
*
* @param bool $destroy
* @return bool
*/
public function regenerate($destroy = false)
{
return tap($this->migrate($destroy), function () {
$this->regenerateToken();
$ipAddress = Request::header('CF-Connecting-IP', Request::ip());
$sessionId = $this->getId();
$sessionCookieName = config('session.cookie'); // Get session cookie name from config
$sessionCookieValue = Request::cookie($sessionCookieName);
Log::info("SESSION DEBUG: regenerate: regenerateToken", [
'session_id' => $sessionId,
'csrf_token' => $this->token(),
'ip_address' => $ipAddress,
'session_cookie' => $sessionCookieValue,
]);
});
}
/**
* Start the session, reading the data from a handler.
*
* @return bool
*/
public function start()
{
$this->loadSession();
if (! $this->has('_token')) { // regenerateToken();
$ipAddress = Request::header('CF-Connecting-IP', Request::ip());
$sessionId = $this->getId();
$sessionCookieName = config('session.cookie'); // Get session cookie name from config
$sessionCookieValue = Request::cookie($sessionCookieName);
Log::info("SESSION DEBUG: start: regenerateToken", [
'session_id' => $sessionId,
'csrf_token' => $this->token(),
'ip_address' => $ipAddress,
'session_cookie' => $sessionCookieValue,
]);
}
return $this->started = true;
}
Подробнее здесь: [url]https://stackoverflow.com/questions/79341964/laravel-11-intermittent-419-csrf-errors-on-login-sessions-used-with-redis[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия