yii2: Yii2 (v 2.0.16-dev) Randomly fail to validate _csrf token on login.
What steps will reproduce the problem?
- Application is Yii2 Advanced Template
- On configurations have these settings:
'user' => [
'identityClass' => 'backend\models\User',
'enableAutoLogin' => false,
'identityCookie' => [
'name' => '_cookieBackend', // unique name
],
'loginUrl' => ['site/login']
],
Also I have ‘cookieValidationKey’ property setted :
'components' => [
'request' => [
// !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
'cookieValidationKey' => 'SOMEKEY',
],
],
- Creating form for Login with ActiveForm (method POST) and Login
What is the expected result?
Login in the application.
What do you get instead?
[yii\web\HttpException:400] yii\web\BadRequestHttpException: Unable to verify your data submission.
Additional info
Q | A |
---|---|
Yii version | 2.0.16-dev |
PHP version | 5.6.30 |
Operating system |
This issue appear Randomly, sometimes I can login successfully and sometimes not. On getting the error reload resolve the problem; I’m redirected inside the application and the user is logged. Disabling csrfValidation resolve the problem but it compromise the application security.
I dumped the function that validate the token:
/**
* Validates CSRF token.
*
* @param string $clientSuppliedToken The masked client-supplied token.
* @param string $trueToken The masked true token.
* @return bool
*/
private function validateCsrfTokenInternal($clientSuppliedToken, $trueToken)
{
if (!is_string($clientSuppliedToken)) {
return false;
}
$security = Yii::$app->security;
var_dump($security->unmaskToken($clientSuppliedToken));
echo "<br \>";
echo "<br \>";
var_dump($security->unmaskToken($trueToken));
echo "<br \>";
echo "<br \>";
var_dump($security->compareString($security->unmaskToken($clientSuppliedToken), $security->unmaskToken($trueToken)));
die;
return $security->compareString($security->unmaskToken($clientSuppliedToken), $security->unmaskToken($trueToken));
}
In some cases variables $clientSuppliedToken and $trueToken have different values causing validateCsrfTokenInternal to return FALSE.
Also reporting this similar issue: 353181592
About this issue
- Original URL
- State: open
- Created 6 years ago
- Reactions: 3
- Comments: 38 (20 by maintainers)
привет)
но дело в том что сейчас это создает проблемы только для “честных пользователей” в ситуациях которую я описал выше при первом заходе на страницу где после загрузки страницы происходят аякс запросы. значение куки изменяется в этом случае а токен в метатеге и скрытых инпутах остается старым.
наверное это не очень здорово так делать я вот поотлаживал и вижу что устаревшие пары кука + токен - все рабочие и с ними можно проходить цсрф защиту - т.е. для “недобросовестных юзеров” (для которых цсрф и включаем) проблем нет - один раз можно получить пару и спамить с ней сколько влезет.
вот на скринах как выглядит тест: https://monosnap.com/file/kKApRHVS2N7ykLkZMXXs3GLXRPk3DB - взял 4 пары кука + токен и прогнал через цсрф защиту https://monosnap.com/file/ithyKc1Cc1QSyHXi7T3edA6B3HaYkm - все 4 пары успешно проходят защиту
т.е. в текущей реализации перегенерация не добавляет стойкости цсрф защите но создает проблемы при штатном использовании сайта где она используется (только при первом посещении за сессию и если со страницы после готовности идут аяксы)
поэтому пока что выкрутились перегрузив этот метод: public function getCsrfToken($regenerate = false) чтобы перегенерации не происходило если токен есть в куках
You could disabled the submit button with javascript
Ah ok - I think I debugged the source of the problem. Its not CSRF but apparently the
exit
in PHP 7.2.x is different.If you have a controller action for an ajax response that returns a JSON like this - you may get a bad request in PHP 7.2
Instead change the above code to something like below: