yii2
yii2 copied to clipboard
Unable to verify your data submission
What steps will reproduce the problem?
Posting a form or post a link where data-method="POST"
What is the expected result?
For or link is submitted
What do you get instead?
yii\web\BadRequestHttpException: Unable to verify your data submission. in /var/www/my.uhub.biz/vendor/yiisoft/yii2/web/Controller.php:166
Additional info
Not sure if this is related to a previously submitted issue (https://github.com/yiisoft/yii2/issues/15783) or it's new. Since that issue was fixed and the project was updated to V2.0.15.1, I still get this error sometimes. The problem is it's not always reproducible and it's hard to pinpoint the problem.
Some scenerios:
- Submit form gets 'Unable to verify your data submission'. But if you reload the form again, the form is submitted.
- Sometimes if you get the error, no matter how many times you reload the form you still get the same error.
- My dev and prod sites uses the same domain (eg dev.domain.com, prod.domain.com) and uses SSO with cookie set in domain.com. If a form is submitted in one site, then when working on the other site and submit a form (can be same or different form) you get the error, but if you reload the form and submit again, it's either 1) or 2) above.
I have checked data in cookies, sesseions and post and can't spot anything. Let me know if you need more info or what else to check.
Q | A |
---|---|
Yii version | 2.0.15.1 |
PHP version | 7.0.28-0ubuntu0.16.04.1 |
Operating system | Ubuntu 16.04 |
The csrf token is different for the environments, could you confirm that the csrf cookie is not shared between those domains?
The csrf cookie is not shared. It's stored in the subdomain.
You share sessions right? Could it be that one site is updating the csrf in the session, thereby invalidating the value for the other domain? (I don't remember if csrf uses the session)
Hmm, it doesn't by default...
Thanks for posting in our issue tracker. In order to properly assist you, we need additional information:
- When does the issue occur?
- What do you see?
- What was the expected result?
- Can you supply us with a stacktrace? (optional)
- Do you have exact code to reproduce it? Maybe a PHPUnit tests that fails? (optional)
Thanks!
This is an automated comment, triggered by adding the label status:need more info
.
I went back to V2.0.13.3 and tested, I don't see this problem - don't get the random 'Unable to verify your data submission error', and tested switched between posting data in dev and prod site, no problem.
V2.0.14.2 and V2.0.15.1 gets random error. Switching site also gets the error.
The switch site problem can be reproduced: simply display a form with single field, and post the form. Then go to the other site and go to the same form, you get the error, then reload the form and post again, the data is posted (only quite rarely the form can't be posted.)
But for the random problem that happens within the same site, it's very random, sometimes the the form can't be post no matter how many time you reload it, then suddenly it's posted.
I have compare session and cookies for V2.0.15 and V2.0.13 but can't spot what's wrong, unless it's hidden behind the random generated strings.
If more info required, can you point me towards the right direction what to look for?
It seems the previous ticket (#15783) is not entirely fixed. There must be some change to V2.0.14 causing this.
Do you know what's the reason of Unable to verify your data submission
somehow via debugging?
- Is it because CSRF token from cookie and submitted HTML form hidden CSRF field differ?
- Or is CSRF token empty?
- Do you have
Request::enableCsrfCookie = true
orfalse
?
I am experiencing similar issue which occurs right after I logout and instantly try to login back - I also get Unbale to verify submission data
. It seems that cookie CSRF token won't get refreshed after user identity reneval, but I have to investigate more to confirm.
Not sure if it is related... I find that this issue occurs for AJAX Requests on latest jQuery releases like 3.2.x. Probably the $.ajaxPrefilter
used by yii.js
does not seem to be executed properly - as the X-CSRF-TOKEN
does not seem to be passed with the ajax request headers.
I included this JS hack (without any jquery dependency) on my main layout view file to get the ajax requests properly send the X-CSRF-TOKEN
and avoid the 400 submission error.
// layouts/main.php
$js = <<< JS
(function() {
var send = XMLHttpRequest.prototype.send,
token = document.getElementsByTagName('meta')['csrf-token'].content;
XMLHttpRequest.prototype.send = function() {
this.setRequestHeader('X-CSRF-Token', token);
return send.apply(this, arguments);
};
}());
JS;
$this->register($js, \yii\web\View::POS_HEAD);
Still unable to figure it :(
I think I've found the root of the problem but don't know how to fix it.
Since V2.0.14, csrf token is regenerated in login() function, hence I'm getting this problem since this version.
As mentioned both are in subdomain and uses SSO login. When site A is loaded, the identity cookie for Site B is lost (it's still in $_COOKIE but not in Yii::$app->request->cookies) and vice versa - hence it tries to login again and got a new csrf token, which results in 'Unable to verify your data submission' error when posting the data.
In this particular test scenario, one site is dev and one site is prod hence the configs are the same.
In component section of config:
'user' => [
'class' => 'common\components\SsoUser',
'identityClass' => 'common\models\User',
'enableAutoLogin' => true,
'enableSession' => true,
'identityCookie' => [
'name' => '_identity',
'httpOnly' => true,
'domain' => '.xxxx.com',
],
],
'session' => [
'name' => 'session-frontend',
'cookieParams' => [
'domain' => '.xxxx.com',
'httpOnly' => true,
],
],
In SsoUser.php, which extends yii\web\User, I have extended login() and set the default duration to 3600. How come the cookie didn't persist but lost? Is it a bug or something wrong with my config?
How come the cookie didn't persist but lost?
Session cookie is meant to expire. You need "remember me" in order to keep logged in state. Chrome does weird things with persisting cookies but it's even against RFCs. But that's not your case.
When site A is loaded, the identity cookie for Site B is lost (it's still in $_COOKIE but not in Yii::$app->request->cookies) and vice versa
That means that A uses same cookie name as B and overwrites it. You need to separate these cookies via config.
Isn't setting the duration in login() = remember me?
I have a different Yii2 project under different subdomain, with different cookie names is causing the same issue.
I did a test on my dev and prod site. Display a page which displays the content of Yii::$app->request->cookies. Changed cookie names for crsf, identity and session with suffiix '-dev' for the dev site.
Open chrome. Clear all cookies. Open a tab to the login site to login. Open a new tab to go to dev site and to the cookies page. On first load, no identity cookie. On subsequent reloads, identity cookie is displayed. Open another tab to go to prod site, display any pages. Go back to the dev tab. Reload. Identity cookie is lost. Reload, it's back, and continue be there until I reload the page in prod tab.
Now they have different cookie names. Overwrite shouldn't happen here?
Facing same issue "Не удалось проверить переданные данные." Althogh, in logs I can see, that both CSRF cookie and CSRF Header has been sent by user
I think that this may happen due to session expiration. User's session is expired, he relogins on one page, but other page is cached in browser and contains old session data. Then user have invalid csrf token on cached page
@cluwong no, it should not. That's super-weird. Am I right that these two website are totally not connected? Separate databases, separate domains (not sub-domains of same domain), separate session storage?
@samdark Would it not be better to revert the commit which caused these issues (csrf token is regenerated in login()
function), until better solution found? Already confirmed by multiple users ...
No. It fixes security issue.
Sorry my bad. I forgot to run the console command to apply the changes and wasn't paying attention to the cookie names. Identity cookie persists when switching between sites when they have different names.
I thought with SSO, by setting the domain, the cookie is available for all subdomains, hence the same cookie name was used so they have the same identity info shared by the subdomains.
So with cookie names, should all 3 cookies have different names? (Although my tests show that only identity cookie needs to be different to prevent this error). Will there be any adverse hidden effects if csrf and session cookies are the same?
Perhaps docs should also be updated about different cookie names too.
If you want no interference — yes. They all should have different names. You may want these to have same cookies if your intent is to be authenticated at subdomains automatically.
I think that this may happen due to session expiration. User's session is expired, he relogins on one page, but other page is cached in browser and contains old session data. Then user have invalid csrf token on cached page
I confirm this type of problem. Typical scenario:
- User sets browser option "Restore previous session after startup" (or like this)
- Logins to web application, works, opens many tabs with different forms
- Close browser
- Open it on next day. Browser can refresh tabs on this step.
- User see login form, submit it. // <-- csrf regenerated!
- Goes to another tab, submit form. For example, "second" login form, if browser refresh tabs after startup (step 4).
- Bad Request because of invalid csrf-token.
@DmLapin It's a side effect of fixing security issue.
Digging into it with @machour.
Were able to reproduce his case as a user.
It's XMLHttpRequest on a particular page.
Welp, in my case, I was using PageCache
which was caching a csrf value..
Oddly enough, I never experienced the problem on my end, with pages not cached by me.
Disabled the cache and waiting for more logs to confirm that I'm a 🤡
The problem is that if the PageCache cache is invalid, the csrf cookie is not set. Cookies are sent here before the csrf is generated here after the Response::EVENT_AFTER_SEND trigger.
Workaround:
public function beforeAction($action): bool
{
$this->request->getCsrfToken();
return parent::beforeAction($action);
}