From b3ba36830b7c8154cbe11a3fe4a2b2574b228819 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Sat, 23 Apr 2011 15:20:19 +0200 Subject: updated the security guide on the updated mass-assignment security scopes addition, and assign_attributes in AR --- railties/guides/source/security.textile | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'railties') diff --git a/railties/guides/source/security.textile b/railties/guides/source/security.textile index f4c1bde5b1..bf4f11f6b4 100644 --- a/railties/guides/source/security.textile +++ b/railties/guides/source/security.textile @@ -418,10 +418,17 @@ To avoid this, Rails provides two class methods in your Active Record class to c attr_protected :admin ++attr_protected+ also optionally takes a scope option using :as which allows you to define multiple mass-assignment groupings. If no scope is defined then attributes will be added to the default group. + + +attr_protected :last_login, :as => :admin + + A much better way, because it follows the whitelist-principle, is the +attr_accessible+ method. It is the exact opposite of +attr_protected+, because _(highlight)it takes a list of attributes that will be accessible_. All other attributes will be protected. This way you won't forget to protect attributes when adding new ones in the course of development. Here is an example: attr_accessible :name +attr_accessible :name, :is_admin, :as => :admin If you want to set a protected attribute, you will to have to assign it individually: @@ -434,7 +441,25 @@ params[:user] # => {:name => "ow3ned", :admin => true} @user.admin # => true -A more paranoid technique to protect your whole project would be to enforce that all models whitelist their accessible attributes. This can be easily achieved with a very simple initializer: +When assigning attributes in Active Record using +new+, +attributes=+, or +update_attributes+ the :default scope will be used. To assign attributes using different scopes you should use +assign_attributes+ which accepts an optional :as options parameter. If no :as option is provided then the :default scope will be used. You can also bypass mass-assignment security by using the +:without_protection+ option. Here is an example: + + +@user = User.new + +@user.assign_attributes({ :name => 'Josh', :is_admin => true }) +@user.name # => Josh +@user.is_admin # => false + +@user.assign_attributes({ :name => 'Josh', :is_admin => true }, :as => :admin) +@user.name # => Josh +@user.is_admin # => true + +@user.assign_attributes({ :name => 'Josh', :is_admin => true }, :without_protection => true) +@user.name # => Josh +@user.is_admin # => true + + +A more paranoid technique to protect your whole project would be to enforce that all models whitelist their accessible attributes. This can be easily achieved with a very simple initializer: ActiveRecord::Base.send(:attr_accessible, nil) -- cgit v1.2.3 From f3b9d3aba8cc0ffaca2da1c73c4ba96de2066760 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Sun, 24 Apr 2011 00:54:48 +0200 Subject: added config.active_record.whitelist_attributes which creates an empty whitelist of attributes available for mass assignment for all models in your app --- railties/guides/source/configuring.textile | 2 ++ railties/guides/source/security.textile | 6 +++--- railties/test/application/configuration_test.rb | 12 ++++++++++++ 3 files changed, 17 insertions(+), 3 deletions(-) (limited to 'railties') diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index 53460b8c36..d7069b31fc 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -229,6 +229,8 @@ h4. Configuring Active Record * +config.active_record.lock_optimistically+ controls whether ActiveRecord will use optimistic locking. By default this is +true+. +* +config.active_record.whitelist_attributes+ will create an empty whitelist of attributes available for mass-assignment security for all models in your app. + The MySQL adapter adds one additional configuration option: * +ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans+ controls whether ActiveRecord will consider all +tinyint(1)+ columns in a MySQL database to be booleans. By default this is +true+. diff --git a/railties/guides/source/security.textile b/railties/guides/source/security.textile index bf4f11f6b4..f87ffdb20d 100644 --- a/railties/guides/source/security.textile +++ b/railties/guides/source/security.textile @@ -459,13 +459,13 @@ When assigning attributes in Active Record using +new+, +attributes=+, or +updat @user.is_admin # => true -A more paranoid technique to protect your whole project would be to enforce that all models whitelist their accessible attributes. This can be easily achieved with a very simple initializer: +A more paranoid technique to protect your whole project would be to enforce that all models define their accessible attributes. This can be easily achieved with a very simple application config option of: -ActiveRecord::Base.send(:attr_accessible, nil) +config.active_record.whitelist_attributes = true -This will create an empty whitelist of attributes available for mass assignment for all models in your app. As such, your models will need to explicitly whitelist accessible parameters by using an +attr_accessible+ declaration. This technique is best applied at the start of a new project. However, for an existing project with a thorough set of functional tests, it should be straightforward and relatively quick to insert this initializer, run your tests, and expose each attribute (via +attr_accessible+) as dictated by your failing tests. +This will create an empty whitelist of attributes available for mass-assignment for all models in your app. As such, your models will need to explicitly whitelist or blacklist accessible parameters by using an +attr_accessible+ or +attr_protected+ declaration. This technique is best applied at the start of a new project. However, for an existing project with a thorough set of functional tests, it should be straightforward and relatively quick to use this application config option; run your tests, and expose each attribute (via +attr_accessible+ or +attr_protected+) as dictated by your failing tests. h3. User Management diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 62697b1bf9..ab3eb4c9e7 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -258,6 +258,18 @@ module ApplicationTests assert_equal res, last_response.body # value should be unchanged end + test "sets all Active Record models to whitelist all attributes by default" do + add_to_config <<-RUBY + config.active_record.whitelist_attributes = true + RUBY + + require "#{app_path}/config/environment" + + assert_equal ActiveModel::MassAssignmentSecurity::WhiteList, + ActiveRecord::Base.active_authorizers[:default].class + assert_equal [""], ActiveRecord::Base.active_authorizers[:default].to_a + end + test "registers interceptors with ActionMailer" do add_to_config <<-RUBY config.action_mailer.interceptors = MyMailInterceptor -- cgit v1.2.3