GET参数验证

时间:2018-08-29 13:42:11

标签: yii2

我遇到的每个Yii2指南/教程都忽略了GET参数的验证。我想知道为什么。

举个例子,看一下这段代码:

public function actionView($id)
{
    /* @var $model ActiveRecord */
    $model = Model::findOne($id);

    if ($model) {
        return $this->render('view', ['model' => $model]);
    } else {
        throw new \yii\web\NotFoundHttpException();
    }
}

我了解到,如果将无效的参数传递给findOne()方法,它将仅返回null并且不会发生任何不良情况。但这真的是最佳做法吗?我一直在尝试对用户输入及其查看方式非常小心,应该在执行任何操作(如数据库调用)之前立即验证用户输入。即使是GET数据,也不只是POST数据。

public function actionView($id)
{
    /* @var $model yii\base\DynamicModel */
    $model = DynamicModel::validateData(['id' => $id], [
        'idValidation' => ['id', integer]
    ]);

    if ($model->hasErrors()) {
        throw new \yii\web\BadRequestHttpException();
    }

    /* @var $model yii\db\ActiveRecord */
    $model = Model::findOne($id);

    if ($model) {
        return $this->render('view', ['model' => $model]);
    } else {
        throw new \yii\web\NotFoundHttpException();
    }
}

您怎么看?我的方法合理还是矫over过正且不必要?

1 个答案:

答案 0 :(得分:4)

如果您正在使用操作参数,则无需再次验证此参数(除非您有特定的原因,例如允许值的封闭式字典,但我想并非如此)。如果您的操作使用了actionView($id)之类的签名,那么Yii将在进一步处理操作之前确保几件事:

  1. $_GET['id']存在,所以$id永远不会是null。如果有人尝试在GET中没有id值的情况下调用此操作,则他将获得BadRequestHttpException异常而没有调用操作。
  2. $_GET['id']是一个标量。这意味着,如果有人尝试将数组传递为id,那么他将获得BadRequestHttpException异常而无需调用操作。

因此,在此时,您可以确定$id是字符串。这足以保证findOne()的安全。即使您期望整数并且有人将blablabla设为$id也没关系-因为没有记录将NotFoundHttpException设为{{1},所以他仍然会得到blablabla }(这是不可能的-id不是有效的整数)-此处无需额外检查。因此,由Gii或Yii文档生成的默认示例是安全的。因此,您的方法实在是太过分了,完全没有必要。


blablabla可以为数组时,情况可能会改变,因为数组允许使用更强大的语法。在以下情况下,您需要格外注意:

  1. 您明确允许使用数组作为操作参数:$id
  2. 您没有使用动作参数,而是直接使用actionView(array $id)参数:$_GET$id = $_GET['id']-在这种情况下,即使您期望标量,$id = Yii::$app->request->get('id')也可以是数组。

在这种情况下,$id的值可能非常令人惊讶。例如,即使您期望使用单个ID,攻击者也可能传递多个ID。或通过将$id传递为['email' => 'user@example.com']来按指定的字段而不是主键进行过滤-即使意图是仅按ID进行过滤,也会通过$id字段(或其他任何字段)搜索用户。在这种情况下,您应该验证此数组以确保它仅包含期望值。

在较早的版本中,这也允许进行SQL注入,因为没有对列名(数组中的键)进行转义(这对email仍然有效)。参见2.0.15 release announcement并附带一些说明。