I use enableCsrfValidation
on my main config
'components' => [
'request' => [
'enableCsrfValidation' => true,
'enableCookieValidation' => true,
'cookieValidationKey' => '[somerandomstring]',
'csrfParam' => '_csrf-backend',
'hostInfo' => YII_ENV_PROD ? Yii::$app->params['hostInfo'] : null,
'csrfCookie' => [
'httpOnly' => true,
'secure' => YII_ENV_PROD,
'sameSite' => 'Lax',
],
],
and here is one of the controller's action (to change the user's fullName
)
public function actionIndex()
{
$model = new ProfileForm();
$model->fullName = Yii::$app->user->identity->full_name;
if ($model->load(Yii::$app->request->post()) && $model->save()) {
Yii::$app->session->setFlash('success', 'Profile updated successfully.');
return $this->refresh();
}
return $this->render('index', [
'model' => $model,
]);
}
here is my profile/index
view
<?php $form = ActiveForm::begin(['layout' => 'horizontal']); ?>
<?= $form->field($model, 'fullName')->textInput(['maxlength' => true]) ?>
<div class="form-group">
<?= Html::submitButton(Yii::t('app', 'Save'), ['class' => 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
From the rendered HTML page, we already get the _csrf param and token, in both the header and the form.
My question is why, from the penetration testing, the attacker still can submit the form using GET method and change the value of user's fullName, even without submitting the csrf token in the form and/or the header (image taken from the BurpSuite application)?
Note: The issue also happens on other controller/action as well, generated from the Gii.
CSRF token is not validated for GET
, HEAD
or OPTIONS
request.
The problem with your code is that Yii2 by default tries to parse request body even for GET
requests.
That's why if you send body with GET
request Yii::$app->request->post()
call will return non-empty array. Submitted data are loaded to model and it's saved.
If you want to be sure data are saved only for POST
requests you should use Yii::$app->request->isPost
or Yii::$app->request->getIsPost()
in your condition.
For example like this:
if (
Yii::$app->request->isPost
&& $model->load(Yii::$app->request->post())
&& $model->save()
) {
// ...
}