Today we are releasing several versions for Yii 2.0.x and official extensions to fix a security issue.
The problem addressed in these patches exists in ActiveRecord shortcut methods findOne() and findAll(), which may
allow SQL injection if input is not prepared properly. We consider this as a security issue in Yii because the documentation for these methods did not contain an explicit warning that there are cases when passing unfiltered user input might be dangerous. Thanks to analitic1983 for making us aware of the issue.
The nature of this issue does not solely exists in the Yii Framework but depends on how an application uses Yii.
We have changed Yii to be more robust against the worst impact of the problem (SQL injection), but applications may still be vulnerable
and changes to application code are necessary in some cases. As a safety measure, findOne() and findAll() are now limited to filter on
columns that are AR properties only.
Check the news announcement for more details
and information on which application code is affected and what needs to be adjusted on upgrade.
For the above example, the SQL injection part is fixed with the patches provided in this release, but an attacker may still be able to search records by different condition than a primary key search and violate your application business logic. So passing user input directly like this can cause problems and should be avoided.
Application code must be adjusted if you have a situation like in this example. If possible, use action parameter binding, like this:
// yii\web\Controller ensures that $id is scalar
public function actionView($id)
{
$model = Post::findOne($id);
// ...
}
This will result in an HTTP Invalid Request response generated by Yii and the action code is never executed in case someone tries to send an array value for $id.
If you are not in action context, check the input value to be scalar and throw an exception yourself.
There is a small chance that the changes cause existing application logic to break, but I assume these cases are very rare.
findOne() and findAll() will now only accept column names for the table of the current record class. Only if you add a join in find() method and use columns of related records in findOne() and findAll(), this will not work anymore.
Another situation could be that you where using SQL expressions as array keys in findOne() or findAll(). This is also not possible anymore.