Security Question

Hi there,

I’ve got a CGridView with links for each entry and each link is like this:

action/view/id/231

The id here is the unique identifier of the Model instance currently being displayed. So there’s a security issue, a user could enter in the browser the URL with any id.

One of the solution I can think of is to maintain an array in the session like this array(0=>231, 1=>245, 2=>432) and the link would be

action/view/index/0

and the controller’s action would figure out from the array that id 231 must be displayed.

Is there a better solution ?

Thanks

Renaud

This is not a security problem of CGridView, it’s an issue of handling actionView, actionUpdate, … in the controller.

But for example you can use scopes there like ‘published’, ‘ownOnly’ …

You have to add the security to your loadModel method in your CRUD-Controller:




class PostController extends Controller

{

        public function actionView($id)

	{

		$this->render('view',array(

			'model'=>$this->loadModel($id),

		));

	}




        public function actionUpdate($id)

	{

		$model=$this->loadModel($id);

                ...

        }





         public function loadModel($id)

	{

                $model=Post::model()->published()->ownOnly()->findByPk((int)$id); //use scopes

		if($model===null)

			throw new CHttpException(404,'The requested page does not exist.');

		return $model;

	}




Your model code





class Post extends CActiveRecord

{

    ......

    public function scopes()

    {

        return array(

            'published'=>array(

                'condition'=>'status=1',

            ),

            'ownOnly'=>array(

                'condition'=>'owner='.Yii::app()->user->id,

            ),

        );

    }

}



Danke Joblo

So in essence what you are suggesting is that I can leave the ids in the URL and just handle the security in the model, making sure that the record does belong to the right person. And I can use scopes to handle this more gracefully.

You always should control the loaded data in the controllers action,

because the url is accessible from everywere (if not filtered in controller accessControl/rules): CGridView, CListview, custom view, enter in the browser …

And using named scopes is a comfortable way to make defined conditions reusable.

You can use it on creating the dataprovider too:







        /**

	 * Lists all models.

	 */

	public function actionIndex()

	{

		if(Yii::app()->user->isGuest())

                   $dataProvider=new CActiveDataProvider(Post::model()->published());

                else

                   $dataProvider=new CActiveDataProvider(Post::model()->ownOnly());


		$this->render('index',array(

			'dataProvider'=>$dataProvider,

		));

	}