In my MVC application I have a page for a user editing their account details such as email address, password etc. In my database a User table holds this data and the primary key is UserId.
On the ChangeAccountDetails view I have created I pass a ViewModel with the data the user should be able to modify on their account. I also store the UserId in the ViewModel which is rendered into a hidden field on my actual view. I have a concern that this is not safe for the reason that on POST action to save the changed data, my service layer loads the persisted version of the User account details that have just been changed by the UserId sent back in the ViewModel.
I have used Fiddler to alter the POST request and changed the UserId to the UserId of another User record in my database, this can have serious problems as someone could potentially change someone elses password and/or other details this way.
Please could someone advise on how I could avoid such a problem when using ViewModels. Is it that using Session in this case is the only way(I know using Session is best avoided but what about for this purpose)?
I do it through a method of encrypted sessionKey this encrypted key holds user details such as ID etc. the hidden field for ID is always zero on the form and this is changed to the ID of my user.UserId.
I have a user model (user) and that model is populated with the decrypted data from the session it is how i deal with userlevel etc.
my unencrypted string looks like this: userid||email||datetimelogin||users-GUID||Real Name||userlevel
this then gets encrypted with there own private key at 255.
Just a thought, good point though i guess for most it is quite easy to forget that people could fiddle with the ID.
the idea above by zasz is perfectly valid too but then you would have to build a view model to account for the extra field of GUID and to account for the missing UserId field.
This is a common problem. It is best solved by not sending the UserID to the client side. Since you do not want to use the server side session, and want to protect your app from malignant users, you have to simulate a session with a Database table. Put your UserId and Random GUID into the table when the user logs in. Make sure this table has only one row for any given UserId (my attempt to simplify - when the user logs in later again update the existing row with a new guid).
Now send the GUID to the client as part of the ViewModel. When updated email etc comes back with the original guid, consult our table to resolve the guid back into user id. Note that this is sort of a rudimentary session, and achieves tamper-proofing. Tampering a GUID to find some other users Guid is nigh-on impossible.
As you rightly feel, sending our DB identitys for any model not only user to the client side as input hidden fields is a bad idea, and every hacker's breakfast as soon as he wakes up, is to look at hidden input fields and tinker around with it.