Mass assignment vulnerability – how to force dev. define attr_accesible? by homakov

Those who don’t know methods attr_accesible / protected – check that article out http://enlightsolutions.com/articles/whats-new-in-edge-scoped-mass-assignment-in-rails-3-1

Let’s view at typical situation – middle level rails developer builds website for customer, w/o any special protections in model(Yeah! they don’t write it! I have asked few my friends – they dont!)
Next, people use this website but if any of them has an idea that developer didnt specify “attr_accesible” – hacker can just add an http field in params, e.g. we have pursue’s name edition. POST request at pursues#update

id = 333 (target’s pursues id)
pursue['name'] = ‘my purses name’
pursue['user_id'] = 412(hacker id)

if code is scaffolded than likely we got Pursue.find(params[:id]).update_attributes(params[:pursue]) in the controller. And that is what I worry about.

After execution that POST we got hacker owning target’s pursue!

I don’t mean that it is Rails problem, of course not. But let’s get it real(Getting Real ok) – most of developers are middle/junior level and most of them don’t write important but not very neccessary things: tests, role checks etc including topic – attr_accesible

how to avoid injections ? What should Rails framework do to force people to keep their rails websites safe? Making attr_accesible necessary field in model? What do you think guys.

attr_accessible(*args)

Specifies a white list of model attributes that can be set via mass-assignment.指定一个model属性的白名单,其可以通过来定制(白名单里面的的值)。

Like attr_protected, a role for the attributes is optional, if no role is provided then :default is used. A role can be defined by using the :as option.

如同attr_protected,添加的attributes 是他的一个选项,如果没有角色被提供,那么会使用:default选项。一个属性role可以在定义的时候使用:as选项(定制别名)

This is the opposite of the attr_protected macro: Mass-assignment will only set attributes in this list, to assign to the rest of attributes you can use direct writer methods. This is meant to protect sensitive attributes from being overwritten by malicious users tampering with URLs or forms. If you’d rather start from an all-open default and restrict attributes as needed, have a look at attr_protected.

这是attr_protected macro(宏)的相反操作: Mass-assignment 将会仅仅只能设定在这个名单中的attributes ,要分派其余的属性的值你可以使用直接的写方法(赋值然后save)。这里意图去保护敏感的attributes防止其被恶意的用户重写或篡改通过forms的URLs。如果你宁愿开始一个默认全部开放以及需要限制某些属性,去看一看attr_protected.

class Customer
  include ActiveModel::MassAssignmentSecurity

  attr_accessor :name, :credit_rating

  attr_protected :credit_rating, :last_login
  attr_protected :last_login, :as => :admin

  def assign_attributes(values, options = {})
    sanitize_for_mass_assignment(values, options[:as]).each do |k, v|
      send(“#{k}=”, v)
    end
  end
end
When using the :default role :

customer = Customer.new
customer.assign_attributes({ “name” => “David”, “credit_rating” => “Excellent”,:last_login => 1.day.ago }, :as => :default)
customer.name # => “David”
customer.credit_rating # => nil
customer.last_login # => nil

customer.credit_rating = “Average”
customer.credit_rating # => “Average”
And using the :admin role :

customer = Customer.new
customer.assign_attributes({ “name” => “David”, “credit_rating” => “Excellent”, :last_login => 1.day.ago }, :as => :admin)
customer.name # => “David”
customer.credit_rating # => “Excellent”
customer.last_login # => nil
To start from an all-closed default and enable attributes as needed, have a look at attr_accessible.

Note that using Hash#except or Hash#slice in place of attr_protected to sanitize attributes won’t provide sufficient protection.