How does this stop mass assignment?
Asked Answered
C

4

6

I wanted to start using attr_accessible with my models to stop the problem with mass assignment. I understand how it works and have researched as much as I could.

What I don't understand is the difference between using update_attributes(params[:my_form]) or create(params[:my_form]) and setting the fields one by one? Aren't both just as vulnerable?

What is the difference between NOT having attr_accessible and doing this...

@model_object = ModelObject.new
@model_object.create(params[:model_object_params])

And having attr_accessible and doing this...

@model_object = ModelObject.new
@model_object.field1 = params[:model_object_params][:field1]
@model_object.field2 = params[:model_object_params][:field2]
@model_object.field3 = params[:model_object_params][:field3]
@model_object.save!

Aren't both these methods of creating the record just as vulnerable? The hacker/cracker could send a url to both these methods and both would do just the same, right?

Or does using attr_accessible and updating the fields one-by-one do something different or somehow become safer?

There's where all these methods I'm finding of using attr_accessible don't make any sense to me. It seems to be doing the same thing two different ways. What am I missing?

Thanks.

Cupping answered 21/6, 2011 at 3:15 Comment(0)
A
7

In the way you are doing it, it does not prevent "mass assignment".

"Mass assignment" is the term used when Rails is handling the assigning of values to attributes in a model. This is typically done in a controller, using the names and values in params.

When you're doing the assigning yourself, it is also "mass assignment", in a way; but you have fine control over what to assign and what not to in this case. So, to save writing that boilerplate assignment code, Rails provides attr_accesible - same control, less code.

To see how it is used:

Presume that a ActivityLog model has an attribute called user_ip_address.

Now, user_ip_address is an attribute in the model, and could be assigned by mass-assignment or by "self-rolled-mass-assignment".

But in both cases that is wrong -- you don't want user-supplied input to set a value for that attribute.

Instead, you want to always find out the actual IP address of the user and assign that value (ignoring any value in params). So you would exclude user_ip_address from attr_accessible and instead assign it yourself.

attr_accessible :all_attributes_except_user_ip_address

@al = ActivityLog.new(params[:model_object_params])
@al.user_ip_address = get_origin_user_ip_address
@al.save

For any information that a user should not be able to change, use attr_accessible and exclude it from the list.

Ambrosane answered 21/6, 2011 at 3:47 Comment(1)
Oh I see, so what I'm doing stops things like the created_by or creator_id fields from being set, but without finer control, the fields that are being sent and I'm assigning could still have malicious data.There's where it was driving me nuts. all these examples basicly just assigned each field manually instead of by passing params hash. Now I see, thanks.Cupping
K
3

The short answer is that it stops field4 from being set implicitly.

The difference is that without attr_accessible a hacker could update a field that is not in your form. With attr_accessible this impossible.

E.g. if your user model has a field is_admin, a hacker could try to create a new admin by posting:

params[:user][:is_admin] = true

If attr_accessible is set (and obviously it shouldn't contain is_admin) this is impossible.

About your example: if your model only has field1, field2 and field3 and there are no other database columns you want to protect, there is no need to use attr_accessible. Hope this makes it clear.

Just remember:

Without any precautions Model.new(params[:model]) allows attackers to set any database column’s value.

Source: http://guides.rubyonrails.org/security.html#mass-assignment

Kingsbury answered 21/6, 2011 at 3:38 Comment(0)
S
2

The idea here is to limit the parameters you will accept for a given model. Then you can test each of them either with a validation or some other code to be sure they fit expected values.

Attr_accessible is intended to limit the "surface" of your model to what you intend to accept and check carefully. In this way you can automatically ignore an injected parameter like :roles => "admin" in case you add that feature to your model

user.update_attributes(params[:user])

Since the roles attribute is not listed in attr_accessible, the user's attempt to become an administrator is fruitless.

You want to handle the validation logic in one place (your model), instead of checking each parameter value in your controller.

Schoolfellow answered 21/6, 2011 at 3:37 Comment(0)
F
2

Mass assignment isn't something you prevent, it's something you control. It's a good feature, one that makes things easier and cleaner, but without some kind of ability to control what gets set via mass assignment it's a potential security hole. attr_accessible, as others have mentioned, provides that control.

Firetrap answered 21/6, 2011 at 4:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.