CSRF validation stopped working

I was working on assets as CSRF validation stopped working.

Error 400 "Unable to verify your data submission" occurs on POST submissions.

Maybe , It’s happening after I removed assets from @web/assets directory.

The same issue happened for my Virtual Machine’s copy of the project, recently and I couldn’t find a solution but disabling CSRF validation. However, It’s not a good idea.

The layout header contains <?= Html::csrfMetaTags() ?> and also post submission parameters includes _csrf.

I cleared browser cache, cookies and flushed application cache using "yii cache/flush-all" command either.

Yii::$app->getRequest()->validateCsrfToken() returns FALSE in yii\web\controller::beforeAction() method, if you mind.

Please, help me to find the murder!

Hi,

Sorry I do not have a solution "out of the box",

but some tips to track down your problem.

I don’t think the deleted assets in @web/assets are causing the problem.

But to be sure:

[list=1]

[*]You have the folder @web/assets?

[*]When you delete everything except the .gitignore file inside the assets folder,

are the assets re-created next time you visit your page?

[*]If no: check permissions for the assets folder.

[/list]

But, like I said, I guess something else is the reason.

So - Some more questions to track down the problem:

[list=1]

[*]You are working on? Windows or Linux/Unix?

[*]Yii2 Advanced or Basic Template?

[*]Framework Version? 2.0.6?

[*]You receive the "Error 400" on ALL post submissions at the entire project-site?

[*]Or only in specific forms / controllers?

[/list]

In your situation I would do:

  • Install a FRESH application template and check if CSRF is working there.

  • If yes: Re-Install the vendor directory.

If the problem persists after above:

There must be something fishy somwhere in your code or configuration.

If you make use of git:

Compare the last working commit/version with your broken one to identify all recent changes.

If you do not use git:

Then I think you have to check the code - file after file until you found it.

Hope this helps somehow.

Regards

I really appreciate your help.

Please let me answer your questions one by one:

But to be sure:

You have the folder @web/assets?

Yes I have it.

When you delete everything except the .gitignore file inside the assets folder,

are the assets re-created next time you visit your page?

Yes they do.

If no: check permissions for the assets folder.

I’m working on Windows 7 and XAMPP, so permissions are not very tricky.

You are working on? Windows or Linux/Unix?

I’m working on Windows 7 for development. However, I have a production copy of the project on a virtual box which is CentOS 7. Although the clone on CentOS was the one which got sick by CSRF let concentrate on Windows 7 for simplicity.

Yii2 Advanced or Basic Template?

Yii2 Advanced

Framework Version? 2.0.6?

Yes 2.0.6

You receive the "Error 400" on ALL post submissions at the entire project-site?

Or only in specific forms / controllers?

[b]I receive the error only in one form in one controller just in Backend. Ajax post submissions to this controller still works. However, They doesn’t include “_CSRF” parameter. I have not changed anything on that controller or form, recently.

I’m not sure if it is not epidemic.[/b]

Install a FRESH application template and check if CSRF is working there.

I did it and CSRF works. It was working for last three months on my main application.

  • If yes: Re-Install the vendor directory.

If it works, it will ignore the problem without getting any solution and it’s risky for production modes if don’t know the origin of the disease. I met a few people with the same problem and no solution out there when I was googling about it.

If the problem persists after above:

There must be something fishy somewhere in your code or configuration.

It’s likely the configuration is guilty but I don’t know how.

If you make use of git:

Compare the last working commit/version with your broken one to identify all recent changes.

I use git. The problem sticks to the project when I back in history so I couldn’t recognize the break point.

I don’t know how CSRF exactly works. It might be I should study on it to solve the problem but it would be great if someone told me what common causes make CSRF validation to fail?

Hey!

This is interesting!

So actually CSRF works everywhere except in one form of one controller?

Then we know where we have to look. ;)

I’m pretty sure the cause is in that view, action, or controller.

To start with something:

How does the form in the affected view look like?

It is a standard ActiveForm?

Or maybe some kind of customized form? ;)

If customized, please try to add this in your form:




<input type="hidden" name="<?= Yii::$app->request->csrfParam; ?>" value="<?= Yii::$app->request->csrfToken; ?>" />



And try again if CSRF for that form is working now.

Regards

It’s an ActiveForm and POST parameters includes _csrf.

I noticed CSRF token which is posted in submission is different from what is generated in header of the page. It’s normal , isn’t it?

I’ve not touched this part of my project for so long and it worked. I was working on assets, URLs, configs and environment directory to separate dev and prod configs when csrf attacked me!

When I back to sunny days using GIT, the problem sticks to the project and It’s weird. Perhaps it tells the problem is somewhere in GIT IGNORED places.

Thanks

Yii2 , CSRF problem and NO solution again?

Csrf token should be the same in meta and in hidden input form field.

Could you paste here the generated source of the page with the form (at least the interesting parts like header and form itself) and then the view file with the form?

Thanks for your consideration.

CSRF in header and in hidden input have the same value but in POST parameters it changes!

I wish codes don’t make everybody more confuse.

Generated view





<!DOCTYPE html>

<html lang="fa">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1">

    <meta name="csrf-param" content="_csrf">

    <meta name="csrf-token" content="dllNR08uZF8gHg4qfmQcKhIWfip6eA87Pw0qKg1lCzw5ARpzO1tVMA==">

    <title>خلق نظرسنجی</title>

    //some css load here

</head>

<body>

        <div class="wrap">

        <nav id="w1" class="navbar-inverse navbar-fixed-top navbar" role="navigation">

       //A nav menu loads here

        </nav>

        <div class="container">

               <div class="poll-create">


    <h1>خلق نظرسنجی</h1>


    

<div class="poll-form">


    <form id="w0" action="/myAppName/backend/web/poll/create" method="post" enctype="multipart/form-data">

<input type="hidden" name="_csrf" value="dllNR08uZF8gHg4qfmQcKhIWfip6eA87Pw0qKg1lCzw5ARpzO1tVMA==">	

    //Hello we are some text input, textarea and select input

</div>	

<img src="http://localhost/myAppName/frontend/web/images/polls/d41d8cd98f00b204e9800998ecf8427e.jpg" alt="">	<div class="form-group field-poll-image">

<label class="control-label" for="poll-image">عکس</label>

<input type="hidden" name="Poll[image]" value=""><input type="file" id="poll-image" name="Poll[image]">


<div class="help-block"></div>

</div>	

//

		<div class="form-group answers panel panel-primary">

		<div class="panel-heading">

			<div class="panel-title">

				<label for="Poll[answer][]">جوابها</label>			</div>	

		</div>	

		<div class="panel-body">

			<div>

				<button type="button" id="Add-answer" class="btn btn-success">اضافه کردن جواب جدید</button>				<ul class='list-group nonsortable'></ul>

			</div>

			<div class="clearfix"></div>

		</div>	

	</div>

			

	

	

    <div class="form-group">

        <button type="submit" class="btn btn-success">خلق</button>    </div>


    </form>

</div>







The _form above submits these:




Array ( [_csrf] => ZjBFVGhTdFMrATIhDhI6HQpaEG0dERMKDGEGJAAwFR0DcxxhPQE8ZA== [Poll] => Array ( [title] => some title [someInput] => 1394-08-04 [someInput] => 1394-08-12 [someInput] => v1,v2 [someInput] => Array ( [0] => last_name [1] => age ) [someInput] => Array ( [0] => last_name [1] => age ) [image] => [answers] => Array ( [0] => Array ( [title] => answer one ) [1] => Array ( [title] => ) ) ) ) 1




Just a thought… You are sending this form to "/myAppName/backend/web/poll/create" from frontend?

No, I’m not. Poll/create is owner of the form in backend and it is sent to its owner. Everything happens in backend.

It’s just a ordinary CRUD in backend for Poll which its model is located in common\models. However, the form is a bit complicated.

I asked because it’s not usual to see url with ‘backend’ or ‘frontend’ + ‘web’ since the standard way is to point domain to that folder so it will be hidden in url.

I’m afraid we’ve got not enough information to help you. It probably requires to take a look at your code in general.

What code did you write?

You still haven’ t given us that information… ;)

You have told us the result and a sketch of the setup, but it would be interesting to learn what you are doing in your code.

Normally, Yii does all the work behind the scenes, and the most common source of error is people who are complicating things by interfering with what Yii does…

I’m working on URLs. Actually, It’s a sample project to see how everything works on Yii2 and how much it is reliable.

Thanks for your help.

I don’t know where I should look for the murder, in this case!

I’m not sure what more information I have to provide you. Which part of my code could be helpful?

This is _form but I’m not sure it helps.




<div class="poll-form">


    <?php $form = ActiveForm::begin(['options'=>['enctype'=>'multipart/form-data']]); ?>

	

    <?= $form->field($model, 'title')->textarea(['rows' => 6]) ?>

	<?php 

		if($model->updateAfterBegin){

			echo $form->field($model, 'begin')->textInput(['class'=>'form-control p-datepicker ','disabled'=>'disabled']); 

		}

		else{

			echo $form->field($model, 'begin')->textInput(['class'=>'form-control p-datepicker']);

		}

	?>


    <?= $form->field($model, 'end')->textInput(['class'=>'form-control p-datepicker']) ?>


    <?= $form->field($model, 'tag')->textInput(['maxlength' => true]) ?>

	

	<?= $form->field($model, 'user_reqs')->listBox(Profile::getRequestedAttributes(),['class'=>'form-control','multiple'=>'multiple','prompt'=>Yii::t('app','None')]) ?>

	

	<?= $form->field($model, 'result_fields')->listBox(Profile::getRequestedAttributes(),['class'=>'form-control','multiple'=>'multiple','prompt'=>Yii::t('app','None')]) ?>

	

	<?php if(Yii::$app->getSession()->hasFlash('answers-error')): ?>

	<div class="bg-danger"> 

		<ol>

	<?php 

		$messages = Yii::$app->getSession()->getFlash('answers-error');

		foreach($messages as $message)

		{

			echo "<li>".$message."</li>";

		}

	?>

		</ol>

	</div>

	<?php endif; ?>

	

	

	

	

	<?= Html::img($model->getImageUrl()); ?>

	<?= $form->field($model, 'image')->fileInput(); ?>

	

	<?php if($model->isNewRecord): ?>

	<div class="form-group answers panel panel-primary">

		<div class="panel-heading">

			<div class="panel-title">

				<?= Html::label(Yii::t('app','Answers'),'Poll[answer][]'); ?>

			</div>	

		</div>	

		<div class="panel-body">

			<div>

				<?= Html::button(Yii::t('app','Add new answer'),['class' => 'btn btn-success' , 'id' => 'Add-answer']); ?>

				<ul class='list-group nonsortable'></ul>

			</div>

			<div class="clearfix"></div>

		</div>	

	</div>

	<?php endif; ?>

	<?php if(!$model->isNewRecord): ?>

	<div class="form-group answers panel panel-primary">

		<div class="panel-heading">

			<div class="panel-title">

				<?= Html::label(Yii::t('app','Answers'),'Poll[answer][]'); ?>

			</div>	

		</div>	

		<div class="panel-body">

			<div>

				<?= Html::button(Yii::t('app','Add new answer'),['class' => 'btn btn-success' , 'id' => 'Trigger-new-field']); ?>

				<div class='new-answer-div'>

					

					<div class='input-group'>

						<?= Html::textInput("Answer[title]",'',['class'=>'form-control','id'=>'newAnswerInput']); ?>

						

						<span class='input-group-btn'>

							<button type='button' class='btn btn-success' id='Add-answer' poll-id='<?= $model->id; ?>'>

							<span class='glyphicon glyphicon-plus'></span>

							</button>

							<button type='button' class='btn btn-danger' id='hide-new-answer'>

							<span class='glyphicon glyphicon-fire'></span>

							</button>

						</span>

					</div>

					

				</div>

				<?= $this->render('@app/views/answer/_form',['answers'=>$model->answers]); ?>

			</div>

			<div class="clearfix"></div>

		</div>	

	</div>

	<?php endif; ?>

	

	

	

    <div class="form-group">

        <?= Html::submitButton($model->isNewRecord ? Yii::t('app', 'Create') : Yii::t('app', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>

    </div>


    <?php ActiveForm::end(); ?>


</div>



I am guessing that you run into trouble because you haven’t set an id for your form.

Try adding ‘id’ => ‘poll-form’ to the arguments for active form.

It didn’t work. However, it worked for so long without id and I created more than 100 polls without any problem. I’m curious about form id now. How does it affect on _csrf validation ?

I think it’s so hard to find a solution without accessing to entire project. By the way, thank you very much for helping me.

I had this problem.first action open your page in another browser.if it is ok that means your csrf is cached.then open your page in Chrome and install EditThisCookie Extension.click on extension and check is your _csrf cookie is duplicated if it’s happen then remove all duplicated _csrf cookies.in your post params add cache: false.

Hi, I got the same error. And in my case I found out that the problem was in POST Content-Length. I increased “post_max_size” and “upload_max_filesize” values in php.ini file and everything works fine now. To figure it out I stoped my script with XDebug at this line in Controller.php file

if ($this->enableCsrfValidation && Yii::$app->getErrorHandler()->exception === null && !$this->request->validateCsrfToken()) {

and then got PHP POST Content-Length warning. Don’t know why $resuest object doesn’t containt csrf tokens if you trying to upload too large files (this is some difficulties between yii2 and php interpreterer, I suppose) and also yii2 doesn’t display any information about it and just return “403 bad request error” just like you didn’t have csrf tokens at all.

I noticed the image field in your form, and thought that you maybe trying to upload too large files.

I used PHP version - 8.0.1, and Yii2 version - 2.0.40.