Trying to understand a YII2 CSRF / #400 error

We have an “alert” email that gets sent out to certain users, with a link to view a certain record using YII2. For example:

https://www.example.com/surveyanswer/view?id=3090

When they click, they get brought to a log in page. This is because of the below in config\web.php:

	'as beforeRequest' => [
			'class' => \yii\filters\AccessControl::className(),
			'rules' => [
				[
					'allow' => true,
					'actions' => ['login', 'error'],
				],
				[
					'allow' => true,
					'roles' => ['@'],
				],
			],
		],	

Once the user inputs a username a password, occasionally they get a 400 error. Here is the output from one such instance according to the runtime\log file:

2020-05-08 13:18:29 [USERNAME REMOVED(628)][error][yii\web\HttpException:400]
yii\web\BadRequestHttpException: Unable to verify your data submission. in
/var/www/html/moc/vendor/yiisoft/yii2/web/Controller.php:190
Stack trace:
#0 /var/www/html/moc/vendor/yiisoft/yii2/base/Controller.php(155):
yii\web\Controller->beforeAction(Object(yii\base\InlineAction))
#1 /var/www/html/moc/vendor/yiisoft/yii2/base/Module.php(528):
yii\base\Controller->runAction('login', Array)
#2 /var/www/html/moc/vendor/yiisoft/yii2/web/Application.php(103):
yii\base\Module->runAction('site/login', Array)
#3 /var/www/html/moc/vendor/yiisoft/yii2/base/Application.php(386):
yii\web\Application->handleRequest(Object(yii\web\Request))
#4 /var/www/html/moc/web/index.php(16): yii\base\Application->run()
#5 {main}
2020-05-08 13:18:29 [USERNAME REMOVED(628)][info][application] $_GET = []

$_POST = [
    '_csrf' =>
'CgVyjqNJTSX[...]FWkLD0hkrdKhOf8ANxjgW7zN8ONAM[...]B7jA=='
    'login-button' => ''
]

$_FILES = []

$_COOKIE = [
    'PHPSESSID' => 'd42m[...]gdv9'
    '_csrf' =>
'2501a5c3979d586[...]006253b690bf6c[...]2a:2:{i:0;s:5:\"_csrf\";i:1;s:32:\"aCOJxNfDldRC[...]C_OiRwV9C\";}'
]

$_SESSION = [
    '__flash' => []
    '__id' => 628
    '__expire' => 1588994309
]

$_SERVER = [
    'REDIRECT_SCRIPT_URL' => '/site/login'
    'REDIRECT_SCRIPT_URI' => 'https://www.example.com/site/login'
    'REDIRECT_HTTPS' => 'on'
    'REDIRECT_SSL_TLS_SNI' => 'www.example.com'
    'REDIRECT_STATUS' => '200'
    'SCRIPT_URL' => '/site/login'
    'SCRIPT_URI' => 'https://www.example.com/site/login'
    'HTTPS' => 'on'
    'SSL_TLS_SNI' => 'www.example.com'
    'HTTP_HOST' => 'www.example.com'
    'HTTP_CONNECTION' => 'keep-alive'
    'CONTENT_LENGTH' => '253'
    'HTTP_CACHE_CONTROL' => 'max-age=0'
    'HTTP_UPGRADE_INSECURE_REQUESTS' => '1'
    'HTTP_ORIGIN' => 'https://www.example.com'
    'CONTENT_TYPE' => 'application/x-www-form-urlencoded'
    'HTTP_USER_AGENT' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36'
    'HTTP_ACCEPT' =>
'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9'
    'HTTP_SEC_FETCH_SITE' => 'same-origin'
    'HTTP_SEC_FETCH_MODE' => 'navigate'
    'HTTP_SEC_FETCH_USER' => '?1'
    'HTTP_SEC_FETCH_DEST' => 'document'
    'HTTP_REFERER' => 'https://www.example.com/site/login'
    'HTTP_ACCEPT_ENCODING' => 'gzip, deflate, br'
    'HTTP_ACCEPT_LANGUAGE' => 'en-US,en;q=0.9'
    'HTTP_COOKIE' => 'PHPSESSID=d42mu5[...]gdv9;
_csrf=2501a5c3979d58643a1[...]06253b690bf6c1b6a97012a%3A2%3A%7Bi%3A0%3Bs%3A5%3A%22_csrf%22%3Bi%[...]y9CX8NXX_GLC_OiRwV9C%22%3B%7D'
    'PATH' =>
'/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin'
    'SERVER_SIGNATURE' => '<address>Apache/2.4.29 (Ubuntu) Server at www.example.com Port 443</address> '
    'SERVER_SOFTWARE' => 'Apache/2.4.29 (Ubuntu)'
    'SERVER_NAME' => 'www.example.com'
    'SERVER_ADDR' => 'xxx.xxx.xxx.xxx'
    'SERVER_PORT' => '443'
    'REMOTE_ADDR' => 'xxx.xxx.xxx.xxx'
    'DOCUMENT_ROOT' => '/var/www/html/moc/web'
    'REQUEST_SCHEME' => 'https'
    'CONTEXT_PREFIX' => ''
    'CONTEXT_DOCUMENT_ROOT' => '/var/www/html/moc/web'
    'SERVER_ADMIN' => 'webmaster@localhost'
    'SCRIPT_FILENAME' => '/var/www/html/moc/web/index.php'
    'REMOTE_PORT' => '64501'
    'REDIRECT_URL' => '/site/login'
    'GATEWAY_INTERFACE' => 'CGI/1.1'
    'SERVER_PROTOCOL' => 'HTTP/1.1'
    'REQUEST_METHOD' => 'POST'
    'QUERY_STRING' => ''
    'REQUEST_URI' => '/site/login'
    'SCRIPT_NAME' => '/index.php'
    'PHP_SELF' => '/index.php'
    'REQUEST_TIME_FLOAT' => 1588958309.551
    'REQUEST_TIME' => 1588958309
]

The crazy thing is, they are technically logged in! If they just click the email again, it goes right to where they need to go, already logged in, and everything works. I don’t understand why this is only happening sometimes. It is making it very hard to track. It also, by FAR, seems to be related to Safari (iOS and Desktop versions). I was running into a similar (I think) issue with the login page. It would seem that if someone stayed at the login page for a long time, they would then get this same error, and a very similar log file. I changed the login file to have a meta-refresh every 10 minutes. This feels like a hack, but has reduced the frequency of error a lot. I’m not storing any session or auth-key data in the “backenduser” table.

I have the “remember me” box on the login page, but I don’t think it actually does anything (should just remove it at some point as I don’t want to use that) at this moment with nothing to back it up in the DB. Here is the relevant component config:

		'session' => [
			'cookieParams' => [
				'secure' => true,
				'httpOnly' => true,
				'sameSite' => yii\web\Cookie::SAME_SITE_LAX,
			],
		],
		'cookies' => [
            'class' => 'yii\web\Cookie',
            'httpOnly' => true,
            'secure' => true
        ],
        'request' => [
            'cookieValidationKey' => '4MlG[...]qK',
        ],
        'cache' => [
            'class' => 'yii\caching\FileCache',
        ],
        'user' => [
            'identityClass' => 'app\models\BackendUser',
			'enableAutoLogin' => false,
			'enableSession' => true,
			'authTimeout' => 36000,
			'loginUrl' => ['site/login'],
        ],

and lastly, SiteController:

    public function actionLogin()
    {
        if (!Yii::$app->user->isGuest) {
            return $this->goHome();
        }

        $model = new LoginForm();
        if ($model->load(Yii::$app->request->post()) && $model->login()) {
            return $this->goBack();
        }

        $model->password = '';
        $this->layout = 'notloggedin';
		return $this->render('login', [
            'model' => $model,
        ]);
    }

I get an email every time this happens (several times a day, out of 100’s of logins), and have dumped countless hours into this. I feel like something is timing out (especially with how Safari handles it), and _csrf tokens aren’t lining up - but I don’t know how to fix it. Please point me in a direction if you can!

NOTE: The above output has been modified by changing URLs to www.example.com, tokens have been modified to have […] in them, Usernames removed, and IPs have been changed to XXX.XXX.XXX.XXX

Hi, I was getting the same error when _csrf token was expired or was not received by a server.
As I can assume, in your case, when a user to long stay on the login page, a session is expired by default it is 1440 sec. all data in $_SESSION are destroyed, and when, after that, the user tries to login you get this error.
As a solution, you can disable _csrf validation for actionLogin, but in my opinion, it is not good idea.
May be it will be helpful for you