Yii2: yii 2.0.14 -> 2.0.15.1 update broke csrf validation

Created on 1 May 2018  路  9Comments  路  Source: yiisoft/yii2

What steps will reproduce the problem?

Update from yii 2.0.14 to 2.0.15.1

What is the expected result?

Working csrf validation.

What do you get instead?

Bad Request (#400)

Additional info

parent::beforeAction($action) fails inside beforeAction of my site controller. Inside Yii::$app->getRequest()->validateCsrfToken(), $trueToken differs from $this->getBodyParam($this->csrfParam) (which is the one from the page's source, meta & input is identical). Looks like trueToken gets regenerated somehow.

I'm using the yii2 advanced template, csrf meta tags are set. The form of the POST is setup as described here: https://yii2-cookbook.readthedocs.io/csrf/ (Adding CSRF protection).

Please note that I haven't changed any line of code between 2.0.14 and 2.0.15.1. I'm able to reproduce the bug by downgrading to 2.0.14.

| Q | A
| ---------------- | ---
| Yii version | 2.0.15.1
| PHP version | PHP 7.0.19
| Operating system | Debian

to be verified bug

Most helpful comment

Is that advanced template w/o modifications? How could we reproduce it?

Nope, we just used the advanced template as base, the site is fully customized.

I'll try to reproduce it with a standard installation.

All 9 comments

Is that advanced template w/o modifications? How could we reproduce it?

according to the diff it could be related to #15783.

relevant changes: https://github.com/yiisoft/yii2/compare/2.0.14...2.0.15.1#diff-12395c67a35c91aa5fc9ac3f6554375fR260

Is that advanced template w/o modifications? How could we reproduce it?

Nope, we just used the advanced template as base, the site is fully customized.

I'll try to reproduce it with a standard installation.

Take a look at this article https://segmentfault.com/q/1010000004450797

Do you have it cached? Getting "503 Service Unavailable" all the time...

I'm a little bit late but currently investigating the problem. Unfortunately, I haven't found the cause yet, but there seems a little difference between my live environment and the default installation (advanced).

When visiting the default site an "advanced-frontend" cookie is set, even when removing the session name and setting 'enableSession' => false in the main config (doing this the cookie is called PHPSESSID). I'm not sure why this cookie is set even if enableSession is false, and why my live env is acting differently with the same config. Maybe someone has an idea?

edit: setting enableSession to true on my live project sets the cookie, but doesn't solve my initial csrf problem.

edit2: I finally found the problem, I was using Yii::$app->user->login() in beforeAction before calling parent::beforeAction($action). Inside Yii::$app->user->login() the function $this->regenerateCsrfToken(); is called (which causes to have two different csrf tokens), this must have been added somehow after 2.0.14.

I switched to Yii::$app->user->setIdentity() to fix the problem, hopefully there are no drawbacks, because no callbacks are called inside setIdentity().

OK, seems not to be bug of the framework itself but edge case. Should work with the change you've made.

Uh... maybe it not goes here, but I have the following form:

<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]); ?>
        <?= Html::input('hidden', \Yii::$app->request->csrfParam, \Yii::$app->request->getCsrfToken()) ?>
        <div class="row">
            <div class="form-group">
                <label for="preview" class="col-md-3 control-label">
                    <?= ($tema->archivoaudio === '') ? "No hay archivo de audio asociado" : $tema->archivoaudio ?>                                   
                </label>
                <div class="col-md-9">
                    <?php
                    if ($tema->archivoaudio !== ''):
                        ?>
                        <span data-toggle="tooltip" title="Eliminar Audio">
                            <?=
                            Html::a('Eliminar Audio', ['enlace/delete-audio', 'id_tema' => $tema->id], [
                                'data' => [
                                    'confirm' => '驴Desea eliminar el archivo de audio?',
                                    'method' => 'get'
                        ]])
                            ?>
                            <?php
                        endif;
                        ?>
                    </span>
                </div>
            </div>
        </div>
        <?= $form->field($tema, 'tituloaudio')->textInput(['maxlength' => true]) ?>

        <?= $form->field($audioFile, 'file')->fileInput(['required' => true]) ?>

        <?php //Html::input('file', 'audio', null, ['required' => true]) ?>

        <div class="form-group">
            <?= Html::submitButton('Guardar', ['class' => 'btn btn-success']) ?>
        </div>

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

I have commented a Html file input to achieve a validation via custom model. As you see, I have set 2 models (an active form and a non activeform). I have set a hidden input with csrf token because the activeform seems not do it with more than 1 model. The data is obviously sent via POST.

With this, the csrf token seems not be sent but tracking via xdebug and browser, the token goes but the request component seems not catch the parameter. Maybe a bug in PHP or in the Framework?

I use PHP 7.2 in LAMP.

@Zerebokep thanks a lot! I tried to generate a model with gii and got this errors, because of this regenerateCsrfToken in login - other tab made requests to REST endpoint and changed token:)

Was this page helpful?
0 / 5 - 0 ratings