Devise's examples and tutorials say me to have something like this in User model:
attr_accessible :name, :password, :password_confirmation, :remember_me
So I have two questions about this.
Why should I make "name" and "password" accessible? I want them to be protected, does devise let me change this?
What on earth do fields like "password_confirmation" and "remember_me" do in user model? Now I can write something like User.find(1).password_confirmation, it works but has no sense at all.
How to deal with that?
You need all four of these fields accessible in order to create the login and sign up forms. You don't have to worry about the password fields in the database, they are just virtual attributes. The actual fields in the database, which you can confirm in the schema, are actually the encrypted_password and salt. It is actually a very functional, proven and secure system. You should focus innovating in the rest of your app and let devise do its work for you, which it does very well.
I think I've found an answer.
Devise uses mass-assignment, and there is nothing you can do about that. There is a Github issue about that: https://github.com/plataformatec/devise/pull/718. I'm working on idea how we can change Devise to avoid it relying on mass-assignment. I will be happy to know your opinion.
As long as Devise takes away your right to define our attr-accessible list, there are two things you can do about that:
a. You can just use attr_readonly along with attr_accessible. It will open door for Devise, but not for your other forms, read Make attributes mass assignable only during creation
b. def mass_assignment_authorizer allows you to define dynamic attr-accessible list, read http://railscasts.com/episodes/237-dynamic-attr-accessible?view=asciicast. IMHO, this way is overkill for this kind of problem.
Related
I'm doing my first steps in Rails and in object-oriented programming.
There is something quite fudemental that I would like to understand: why do we need attr_accessible within the model?
I have read that hackers can use mass-assignment in order to change database entries and therefore compremise security, and that's why sensitive fields need protection (using atribute_protected in this case).
Is attr_accessible the opposite of atribute_protected? If so, why do we need to state which fields are accessible and which are not? aren't those fields accessible by defult? And what is attr_accessor used for?
I noticed that if I don't make some fields acessible, my application doesn't run. Can I use attr_acessible for sensitive fields like :password_digest and :admin?
It would be amazing if someone could explain it to me.
All the best,
TimmyOnRails
You've got a couple of concepts mixed together here, so I'll try to untangle them.
attr_accessor is for setting up a readable and writable attribute. It is the equivalent of saying attr_reader and attr_writer. Since your question isn't directly about attr_accessor, I won't address it anymore than saying check out this link on Accessors.
According to the Rails docs: attr_accessible is the opposite of the attr_protected macro
You're correct that these methods are used to prevent Mass Assignment vulnerabilities.
attr_accessible says which attributes can be set by mass assignment.
attr_protected says which attributes cannot be set by mass assignment.
So what's the use case for each? In one case you're able to set a global config option that makes it so that all attributes must be declared attr_accessible:
config.active_record.whitelist_attributes = true
In that case you'd use attr_accessible frequently.
And attr_protected? If you went the opposite way and said false on whitelisting attributes, how would you declare which attributes shouldn't be mass assignable? If you said attr_protected you're right! :D
Typically you'd want to set fields like :admin as attr_protected because you don't want an attacker coming in and escalating their privileges to an admin role.
Mass assignment is not something that's easy to get right. Big, smart development teams have gotten this wrong. So tred carefully and make sure you understand what's going on!
I've followed the rails tutorial and have a working users system, but one thing annoys me: When saving a user, even just in the console, I have to turn off validations since it will not save without both password and password confirmation saved, and set to the same thing.
This is a pain, and seems potentially dangerous if I added other important validations to the user. So is there a good way of dealing with this? Really I want the validation to apply only when the update is coming from the user, not from my own code.
So the user model has this:
validates :password, length: { minimum: 6 }
has_secure_password # this does the hashing, comparisions, etc for us.
validates :password_confirmation, presence: true
This works great when the user is created, and for when the user is editing his/her profile since it requires that the password is entered again. But, for other edits, it's annoying. eg:
user = User.find_by_name("bob")
user.reputation = 200
user.save(validate: false) # I really don't want to have to care about password validations here.
You can call
#user.save(:validate => false)
You could try just validating on create. That will make it so the password (or other variables) is only necessary on registration but not when youre editing an existing user.
If you want to have control over which attributes to skip validations for, you may want to try using the ValidationSkipper gem:
https://github.com/npearson72/validation_skipper
Why don't you just create different models for it, a secure model for logging & password changes, and a profile model for anything else, giving out reputations, medals, and stuff.
Creating new functions in the first model allows you to totally forget about the second one, like
def reputation value
self.profile.reputation = value
self.profile.save
end
A little late to the party but if you want to update a single attribute you can use the update_attribute method which skips validation checks. In this case you could call
user.update_attribute :reputation, 200
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.
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.
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
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.
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.
I have a similar situation to this question, which was already posted. Koraktor has asked
I'm using a simple model for user authorisation with two ActiveRecords User and Role User and Role have a HABTM relation to each other.
.
.
Manually assigning roles with #user.roles or #user.role_ids works, but not the "magic" inside User#new or User#update_attributes.
Oleg suggested that
attr_accessible :role_ids
be added to the user model. This would allow mass assignment operators to update roles. However, he cautioned against using this approach because of security concerns.
I have a follow up question to Oleg's response -
In this situation, is there a recommended method to update roles without using mass-assignment?
Also, assuming
you authenticate users,
only allow administrators to CRUD users by putting a before_filter in the users_controller,
is mass-assignment of role_ids still a valid concern?
Mass assignment is a feature of Rails provided for using less code for updating a model like this
Model.create(params[:model])
#model.update_parameters(params[:model])
instead of
#model.field1 = params[:model][:field1]
#model.field2 = params[:model][:field2]
...
#model.save
But with this feature, comes the risk of updating values which we dont intend. For example, if we want just field1, field2 and field3 to be updated by the user and you use update_parameters for mass assignment, there is a risk of updating field4, if one is passing model[user][field4]=some_value either from url or by any other ways. If we are explicitly assigning the fields in the code, we do not have this risk. But then we will have to set the values for each field(wherever we are updating or creating) which is not very productive.
So, for using the mass assignment feature, we have 2 options. First is attr_protected
attr_protected :field4
This will protect field4 from being saved from mass assignment from params[:model] even if it contains field4. For saving field4, we have to call the setter for field4 explicitly in
the code(#model.field4 =). But, the problem with attr_protected is that Rails may provide some other attributes that we may not know for mass assignment. For example, if we define
has_many :model2s
in Model.rb, Rails will provide a method model2_ids= automatically and this can be accessed by mass assignment.(If we give model[model2_ids]= in the url, it will create associations, not intended at all). So, there is a chance of missing attributes like this while using attr_protected.
So, the recommended method is to use attr_accessible
attr_accessible :field1, :field2, :field3
This will make these fields open for mass assignment and all other attributes in the model not available for mass assignment. So, the recommended way is to make those attributes which we are providing in a form for users to edit as attr_accessible and all other parameters will be protected. But, while using this you have to make sure you have included all the attributes you need for edit as attr_accessible.
In your case, since you want the user to edit the role_ids and you are providing access to CRUD for admin users only, I think you can use attr_accessible :role_ids. The alternative would be to assign role_ids explictely like .role_ids = params[:user][:role_ids]. You should use this, if you have another form where you dont want the user to edit the role_ids.
I'm doing a security audit on a Rails 2.3.8 application and one of the things that has come up is our lack of attr_protected or attr_accessible in my model definitions. I understand the reasoning behind them, and have even written a gem to assist with mass assignment, but I'm looking for attributes that I might potentially be missing.
The problem I have is determining which fields should be protected. Are there any rules that people generally follow for this? I'm thinking attributes like foreign keys and booleans like admin? would make sense to protect. I'm also wondering about fields like STI type, and polymorphic *_type/*_id fields. I see that Rails 3 introduced attributes protected by default, but it doesn't appear that Rails 2.3.8 has this.
Any guidance on this would be greatly appreciated.
My general rule of thumb is that any attribute you don't want users to modify should be protected.
So in my models, I use attr_accessible for all attributes that are present as fields in forms. All others are protected. (I'd rather have everything protected by default.)
In other words: assume all data sent by clients will be maliciously tampered.
Edit: relevant blog post http://www.kalzumeus.com/2010/09/22/security-lessons-learned-from-the-diaspora-launch/
I guess every "potentially dangerous" attribute should be protected, like an admin flag for a user.
In my opinion, ideally, every model should have attr_accessible for all attributes that can be updated. It's the safer solution.