Prevent Form Tampering

I’ve searched, but I can’t find out if Yii has an automatic way to prevent form tampering. The only thing I can find is: http://www.yiiframework.com/forum/index.php/topic/10152-csrf-help/page__view__findpost__p__50150

This is NOT csrf validation, I’ve got that turned on, and it is not cookie protection which I also have turned on. I want it so the request fails if the user has modified any hidden inputs or is trying to post different variables than what I outputted on the page. I know ASP.NET does this, as long as you use their controls, where if the user tampers with the form submission data (ie, using Firebug to modify variables - in particular, hidden inputs which aren’t meant to be editable), then the request fails with a big fat exception. This is what I’m after, so basically assuming I use CActiveForm or some variant, it would “keep track” of the inputs and then validate them on post.

The reason is to prevent the user from submitting, for instance, id = 3 instead of id = 2, causing me to do an improper lookup. I know that in an ideal world I would check for this, but that will get very tedious fast in a large application. Since the problem boils down to just making sure what is posted to the server is what I expected, it seems like there should be a way to handle this automatically.

Anyone know how might I go about implementing this? Thanks in advance.

There is currently no solution for this… but why are you setting all those hidden variables… can you go without them and assign those values directly in the controller when the form is submitted?

I don’t have “a lot” of hidden fields, but I’m not sure how else I would manage lists of things. If I’m thinking of this the wrong way I’m happy to be corrected. Concrete example. Let’s say I’m managing a user’s picture album, and he has the ability to set captions on each picture. The way I would expect to do this is something like this (really simplified - and this is quick pseudocode so no need to nitpick if it doesn’t actually run):

<form>

<?php foreach($pics as $pic) { ?>

<img src="<?= $pic->src ?>" />

<label>Caption: </label>

<input type="text" value="<?= $pic->caption ?>" name="UserPicture[<?= $pic->id ?>[caption]" />

<?php } ?>

<input type="submit" />

</form>

Then server side:

foreach($_POST[‘UserPicture’] as $id => $picture) {

$model = UserPicture::model()->findByPk($id); // this is the dangerous part, currently

$model->setAttributes($picture);

$model->save();

}

So, the form gets generated with each user’s picture, along with its id because I need to know which picture to update. But I also want to make sure that the user hasn’t messed with the id parameter and make it so that he can set another user’s picture caption. I know I could do this on a case by case basis by checking that the $model returned really belongs to the user, or even using a defaultScope to make sure that the picture returned will always include the current user’s id in the criteria. This is actually what I will probably end up doing. But I was wondering if a) maybe I’m thinking about it wrong (quite possible), or B) maybe it would be easy to implement this security mechanism manually once, and then I never really have to think about it again.

edit: in the form above normally I would use CHtml::textField() to generate the inputs. I think this is the only way the server would have a hope of keeping track of the inputs.

Use Authentication and authorization. RBAC can help if your setup isn’t simple.

Basically, you will check whether the pic being modified is owned by the currently logged-in user.

The user id can be part of the URL where the form is submitted… and then in the controller you check that the id is from the current user…

This does not prevent me from manually changing the ID of a picture and thus updating the caption of a picture, which belongs to another user.

Of course, the user ID can be once checked in the controller, if its the same as the logged user ID, and then used as a condition, when loading the pictures from the server( if that is what you meant, but in any case passing the user ID in the form makes no sense - we already have it in the session ), but I still think that explicitly checking the owner of every picture is the best and most secure way to go.

Plus I don’t see where’s the problem with this … its done in a loop and means adding 2-3 more lines.

Maybe I did not understand your example (because you did not put there the hidden field)

As I see this… in any case you need to check if the picture belong to the currently logged user, right? so if this ID comes from the hidden field or from the URL… regarding the checking it’s the same.

I don’t see how would a hidden ID value checking be more secure when it’s subject to user tampering.

Is this a reply to my post, or the author’s? :)

Because here I agree with you - only the picture ID is required as input from the form ( and of course the new caption ).

Sorry genn, yes I answered to your post (no quote = answer to the previous post), but I did not check who wrote it and just assumed it’s the author :D

Everyone seems to think the best way is to just manually verify a check. This is fine, I just think it is prone to error because I have to remember to do this everywhere (I’m concerned not only for this one simple situation, but for all situations where I’ll have to make this kind of check).

Regardless, I think I have a halfway solution. When the user submits the form I first retrieve the existing image record (by ID) from the database using a default scope that checks that the owning user is = the current user.

public function defaultScope()


{


    return 


        array(


            'condition' =&gt; 'owning_user_id = :user_id',


            'params' =&gt; array(':user_id' =&gt; Yii::app()-&gt;user-&gt;id),


        );


}

So a lookup for UserPicture::model()->findByPk(5) would only retrieve the image if the current user actually owns picture 5. Since it happens mostly behind the scenes it satisfies my concern about possibly forgetting to include the check. And later when I display the images to the public, I can retrieve them by overriding the default scope using resetScope().

Is there a flaw in this implementation?