kralco626
kralco626

Reputation: 8624

.NET MVC preventing forged POST

SITUATION:

I have a Model and based on a users Role I want to allow the user to only update certain parts of the model. Lets say the Model has three fields. (My Model is obviously more complex than this)

MyObject
Field1
Field2
Field3

My View looks something like this:

Html.TextBoxFor(@Model.Field1)
Html.TextBoxFor(@Model.Field2)
@if(UserIsAdmin())
    Html.TextBoxFor(@Model.Field3)
else
    @Model.Field3

Bearing with me on the syntax (and the poor design of the example), you can see what I'm trying to do. Upon the user posting the form my controller would just take the MyObject and save it back to the database, we are using EF.

QUESTION:

My question is, is there a way to stop a user from forging a POST to be able to save data he/she should not be able to. My current idea would be to do a check in the controller to see if the user modified values he should not have. Or I could save fields individually, but neither is a convient solution.

Is there a better one?

Thanks!

Additional Info:

Not sure if this artical is relevant at all: http://blog.stevensanderson.com/2008/09/01/prevent-cross-site-request-forgery-csrf-using-aspnet-mvcs-antiforgerytoken-helper/

All three fields are from the same database table and I'm using EF to get and save the entity.

Upvotes: 3

Views: 165

Answers (3)

CodeCaster
CodeCaster

Reputation: 151588

My current idea would be to do a check in the controller to see if the user modified values he should not have. Or I could save fields individually, but neither is a convient solution.

You're on the right track with that idea. A typical Add() operation would look like this:

public class FooController : Controller
{
    public ActionResult Add(FooViewModel viewModel)
    {   
        if (ModelState.IsValid)
        {
            FooDataModel dataModel = FooMapper.MapToDataModel(viewModel, User);
            FooRepository.Add(dataModel);
        }   
    }
}

Like @VimalStan said, your FooViewModel is then a model that contains only the fields you want to let the user update. Also this still doesn't solve your problem, which should be done in your mapper (in this case FooMapper) and still check every field as @Ben suggested:

public static class FooMapper
{
    public static FooDataModel Map(FooViewModel viewModel, IPrincipal user)
    {
        var dataModel = new FooDataModel();

        dataModel.Field1 = viewModel.Field1;
        dataModel.Field2 = viewModel.Field2;

        if (IsAllowedToUpdateField3(user))
        {
            dataModel.Field3 = viewModel.Field3;
        }

        return dataModel;
    }

    public static bool IsAllowedToUpdateField3(IPrincipal user)
    {
        return false; // your logic
    }
}

Upvotes: 1

Ben
Ben

Reputation: 35613

You want to make sure the user is only able to update permitted fields.

You decided that the way to achieve this is to prevent the user "forging" a response using e.g. firebug, or F12 developer tools, or GreaseMonkey, and have asked how to do this.

But the correct/best method is to check which fields the user is attempting to update, and only update those which he is permitted to update. Then it doesn't matter if they forge the request or not, they still won't be able to access anything they shouldn't. In other words, check access rights at the point of access.

Anti-forgery tokens are there to solve a separate problem, namely XSRF.

Upvotes: 3

Vimal Stan
Vimal Stan

Reputation: 2005

Use a viewmodel that accepts only the fields that should be updated and then populate the model with those values. You could use something like AutoMapper for mapping between the two.

Upvotes: 2

Related Questions