26 Marattr_accessible and mass-assignment

Friday, 26 March 2010 — 23:31

It’s always a good practice to use attr_accessible in your models, to protect sensible attributes from being filled through the technique known as mass-assignment. With mass-assignment we understand methods such as: new(attributes), update_attributes(attributes), or attributes=(attributes), that allow us to create new records very easily.

So, on one side, we can keep skinny controllers using mass-assignment, but on the other side, we can create a vulnerability in our code for hackers, to inject sensitive information in our models, like passwords, user admins, owner and so on…

From API doc, here is a clear example:

class Customer < ActiveRecord::Base
    attr_accessible :name, :nickname
  end

  customer = Customer.new(:name => "David", :nickname => "Dave", :credit_rating => "Excellent")
  customer.credit_rating # => nil. Not accessible
  customer.attributes = { :name => "Jolly fellow", :credit_rating => "Superb" }
  customer.credit_rating # => nil. Not accessible

  customer.credit_rating = "Average"
  customer.credit_rating # => "Average", It is accessible

It can be tedious, as you need to add all accessible methods there, or you will get:

WARNING: Can't mass-assign these protected attributes

But even with that, attr_accessible should be the way to go. If you have a long list of items, you can use attr_protected instead. BUT there is one more thing to take into account.

When you add attr_accessible to your models, ActiveRecord will protect it from mass-assignment as expected, but will also remove not acceptable attributes on mass-assignment. Let’s continue with previous Customer class example:

customer.attributes = { :name => "Jolly fellow", :credit_rating => "Superb", :non_existing_attr =>"whatever" }

and this returns:

WARNING: Can't mass-assign these protected attributes: non_existing_attr

but it’s just a warning. If we remove the attr_accessible line from the model, we will get a NoMethodError exception instead:

NoMethodError: undefined method `non_existing_attr='

The reason is in ActiveRecord. When we call attributes=, and we have attr_accessible/attr_protected set, this is executed:

attributes = remove_attributes_protected_from_mass_assignment(attributes) if guard_protected_attributes
...

def remove_attributes_protected_from_mass_assignment(attributes)
..
attributes.reject { |key, value| !self.class.accessible_attributes.include?(key.gsub(/\(.+/, "")) || attributes_protected_by_default.include?(key.gsub(/\(.+/, "")) }
...
end

So to sum up, those params not in attr_accessible are removed, and you will never get an exception. Take this into account when you use attr_accessible

Comentarios

Añade tu comentario




(textile habilitado)
Negrita: *Google*
Enlace: "google.com":http://www.google.com
Imagen: !http://ggomeze.com/images/avatar.png!

ó Cancelar