Why does Massive Assignment fail?
As "obvious" as Massive Assignment is, it's remarkably common for
users to find that their $modelvariables fail to ->save() due to
missing field values. Either the validation is failing outright, or
field values are not copied from the form to the $model.
Key Point - Massive Assignment will only be made for fields which have passed some explicit validation rule. The obvious "actual" validators - length, email, required, etc. - all qualify, but some fields are free form and optional, and don't have any format requirements - the user can put whatever he likes, including leaving it blank.
For some fields, there's nothing to validate, right?
Wrong: by only assigning field values that the user has explicitly said are eligible for copying into $model, this limits shenanigans of a bad guy trying to pollute a model.
Even if a field has no particular data-format validations, we still have to tell Yii we want the attribute copied during Massive Assignment. This is done with the 'safe' validator.
Attributes that do not appear in any validation rule are not copied to the $model. Period.
So what's the big deal?
It's a very common question to wonder why this "safe" business is
required at all.
After all, if the developer configures the form with certain fields, shouldn't they all just be copied to the $model after validation has passed? Why isn't this good enough?
Because Yii is protecting you from security surprises.
Though it may seem obvious to accept all the fields built into a form, during the controller's action (where Massive Assignment is taking place), Yii has no way of knowing which actual fields were part of a the form. and which are from a bad guy who is synthesizing form input with a contrived POST in order to fool the application.
This is protecting against two scenarios:
Some models have attributes that are legitimate (in general), but not in a specific form. For instance, a change-your-password form for a user should accept the password and passwordRepeatattributes, but not the isAdmin attribute that makes him an administrator of the application. For a changePassword scenario, isAdmin should be marked explicitly 'unsafe'.
All model objects based on CActiveRecord have internal housekeeping attributes that are subject to shenanigans if the bad guy were able to make assignments to them. Some of these include:
$model->isnewrecord
$model->dbcriteria
$model->primarykey
$model->tablealias
$model->scenario
and perhaps others. It's rather scary to think what could happen if
the bad guy were able to manipulate these with malicious input, but
because they are not mentioned in any validation rule -'safe' or
otherwise - they are protected.
Yii takes the conservative approach that attributes are assumed to be unsafe unless the developer explicitly makes them so (a "default deny" paradigm), rather than the easier but more dangerous "default allow".
It's wise to review the Rules in your model from time to time to ensure that you're not allowing things you should not (especially when scenarios are in play), because it's not uncommon to wildly mark things as safe during a bout of validation problems without realizing that this actaully reduces the security of the application.