diff options
-rw-r--r-- | Gemfile | 7 | ||||
-rw-r--r-- | actionpack/CHANGELOG.md | 70 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/mime_type.rb | 7 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/asset_tag_helper.rb | 11 | ||||
-rw-r--r-- | actionpack/test/dispatch/mime_type_test.rb | 8 | ||||
-rw-r--r-- | actionpack/test/dispatch/rack_test.rb | 12 | ||||
-rw-r--r-- | actionpack/test/template/asset_tag_helper_test.rb | 2 | ||||
-rw-r--r-- | activerecord/lib/active_record/associations/association.rb | 7 | ||||
-rw-r--r-- | activerecord/test/cases/associations/extension_test.rb | 7 | ||||
-rw-r--r-- | activerecord/test/cases/transaction_isolation_test.rb | 6 | ||||
-rw-r--r-- | guides/source/security.md | 137 | ||||
-rw-r--r-- | railties/lib/rails/rack/logger.rb | 2 |
12 files changed, 167 insertions, 109 deletions
@@ -39,7 +39,12 @@ instance_eval File.read local_gemfile if File.exists? local_gemfile platforms :mri do group :test do gem 'ruby-prof', '~> 0.11.2' - gem 'debugger' if !ENV['TRAVIS'] && RUBY_VERSION < "2.0" + end +end + +platforms :mri_19 do + group :test do + gem 'debugger' unless ENV['TRAVIS'] end end diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 5a3b4dc4a2..248677688f 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,5 +1,15 @@ ## Rails 4.0.0 (unreleased) ## +* `image_tag` will set the same width and height for image if numerical value + passed to `size` option. + + *Nihad Abbasov* + +* Deprecate Mime::Type#verify_request? and Mime::Type.browser_generated_types, + since they are no longer used inside of Rails, they will be removed in Rails 4.1 + + *Michael Grosser* + * `ActionDispatch::Http::UploadedFile` now delegates `close` to its tempfile. *Sergio Gil* * Add `ActionController::StrongParameters`, this module converts `params` hash into @@ -86,26 +96,26 @@ end end -* Add automatic template digests to all CacheHelper#cache calls (originally spiked in the cache_digests plugin) *DHH* +* Add automatic template digests to all `CacheHelper#cache` calls (originally spiked in the cache_digests plugin) *DHH* * When building a URL fails, add missing keys provided by Journey. Failed URL generation now returns a 500 status instead of a 404. *Richard Schneeman* -* Deprecate availbility of ActionView::RecordIdentifier in controllers by default. +* Deprecate availbility of `ActionView::RecordIdentifier` in controllers by default. It's view specific and can be easily included in controller manually if someone - really needs it. RecordIdentifier will be removed from ActionController::Base - in Rails 4.1 *Piotr Sarnacki* + really needs it. RecordIdentifier will be removed from `ActionController::Base` + in Rails 4.1. *Piotr Sarnacki* -* Fix ActionView::RecordIdentifier to work as a singleton *Piotr Sarnacki* +* Fix `ActionView::RecordIdentifier` to work as a singleton. *Piotr Sarnacki* -* Deprecate Template#mime_type, it will be removed in Rails 4.1 in favor of #type. +* Deprecate `Template#mime_type`, it will be removed in Rails 4.1 in favor of `#type`. *Piotr Sarnacki* -* Move vendored html-scanner from action_controller to action_view directory. If you +* Move vendored html-scanner from `action_controller` to `action_view` directory. If you require it directly, please use 'action_view/vendor/html-scanner', reference to - 'action_controller/vendor/html-scanner' will be removed in Rails 4.1 *Piot Sarnacki* + 'action_controller/vendor/html-scanner' will be removed in Rails 4.1. *Piot Sarnacki* * Fix handling of date selects when using both disabled and discard options. Fixes #7431. @@ -116,12 +126,12 @@ Setting `config.session_store` to `:active_record_store` will no longer work and will break if the `activerecord-session_store` gem isn't available. *Prem Sichanugrist* -* Fix select_tag when option_tags is nil. +* Fix `select_tag` when `option_tags` is nil. Fixes #7404. *Sandeep Ravichandran* -* Add Request#formats=(extensions) that lets you set multiple formats directly in a prioritized order *DHH* +* Add `Request#formats=(extensions)` that lets you set multiple formats directly in a prioritized order. Example of using this for custom iphone views with an HTML fallback: @@ -134,6 +144,7 @@ end end + *DHH* * Add Routing Concerns to declare common routes that can be reused inside others resources and routes. @@ -165,9 +176,9 @@ *DHH + Rafael Mendonça França* -* Add start_hour and end_hour options to the select_hour helper. *Evan Tann* +* Add `start_hour` and `end_hour` options to the `select_hour` helper. *Evan Tann* -* Raises an ArgumentError when the first argument in `form_for` contain `nil` +* Raises an `ArgumentError` when the first argument in `form_for` contain `nil` or is empty. *Richard Schneeman* @@ -209,9 +220,9 @@ *Armand du Plessis* -* Fixed issue with where Digest authentication would not work behind a proxy. *Arthur Smith* +* Fixed issue with where digest authentication would not work behind a proxy. *Arthur Smith* -* Added ActionController::Live. Mix it in to your controller and you can +* Added `ActionController::Live`. Mix it in to your controller and you can stream data to the client live. For example: class FooController < ActionController::Base @@ -227,7 +238,9 @@ end end -* Remove ActionDispatch::Head middleware in favor of Rack::Head. *Santiago Pastorino* + *Aaron Patterson* + +* Remove `ActionDispatch::Head` middleware in favor of `Rack::Head`. *Santiago Pastorino* * Deprecate `:confirm` in favor of `:data => { :confirm => "Text" }` option for `button_to`, `button_tag`, `image_submit_tag`, `link_to` and `submit_tag` helpers. @@ -267,7 +280,7 @@ *Jeremy Friesen* -* Make possible to use a block in button_to helper if button text is hard +* Make possible to use a block in `button_to` if the button text is hard to fit into the name parameter, e.g.: <%= button_to [:make_happy, @user] do %> @@ -470,27 +483,28 @@ * Add `:format` option to number_to_percentage *Rodrigo Flores* -* Add `config.action_view.logger` to configure logger for ActionView. *Rafael Mendonça França* +* Add `config.action_view.logger` to configure logger for Action View. *Rafael Mendonça França* -* Deprecated ActionController::Integration in favour of ActionDispatch::Integration +* Deprecated `ActionController::Integration` in favour of `ActionDispatch::Integration`. -* Deprecated ActionController::IntegrationTest in favour of ActionDispatch::IntegrationTest +* Deprecated `ActionController::IntegrationTest` in favour of `ActionDispatch::IntegrationTest`. -* Deprecated ActionController::PerformanceTest in favour of ActionDispatch::PerformanceTest +* Deprecated `ActionController::PerformanceTest` in favour of `ActionDispatch::PerformanceTest`. -* Deprecated ActionController::AbstractRequest in favour of ActionDispatch::Request +* Deprecated `ActionController::AbstractRequest` in favour of `ActionDispatch::Request`. -* Deprecated ActionController::Request in favour of ActionDispatch::Request +* Deprecated `ActionController::Request` in favour of `ActionDispatch::Request`. -* Deprecated ActionController::AbstractResponse in favour of ActionDispatch::Response +* Deprecated `ActionController::AbstractResponse` in favour of `ActionDispatch::Response`. -* Deprecated ActionController::Response in favour of ActionDispatch::Response +* Deprecated `ActionController::Response` in favour of `ActionDispatch::Response`. -* Deprecated ActionController::Routing in favour of ActionDispatch::Routing +* Deprecated `ActionController::Routing` in favour of `ActionDispatch::Routing`. -* check_box helper with :disabled => true will generate a disabled hidden field to conform with the HTML convention where disabled fields are not submitted with the form. - This is a behavior change, previously the hidden tag had a value of the disabled checkbox. - *Tadas Tamosauskas* +* `check_box helper` with `:disabled => true` will generate a disabled + hidden field to conform with the HTML convention where disabled fields are + not submitted with the form. This is a behavior change, previously the hidden + tag had a value of the disabled checkbox. *Tadas Tamosauskas* * `favicon_link_tag` helper will now use the favicon in app/assets by default. *Lucas Caton* diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index f86ae26b8a..3d560518e1 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -57,7 +57,6 @@ module Mime # i.e. following a link, getting an image or posting a form. CSRF protection # only needs to protect against these types. @@browser_generated_types = Set.new [:html, :url_encoded_form, :multipart_form, :text] - cattr_reader :browser_generated_types attr_reader :symbol @register_callbacks = [] @@ -276,9 +275,15 @@ module Mime # Returns true if Action Pack should check requests using this Mime Type for possible request forgery. See # ActionController::RequestForgeryProtection. def verify_request? + ActiveSupport::Deprecation.warn "Mime::Type#verify_request? is deprecated and will be removed in Rails 4.1" @@browser_generated_types.include?(to_sym) end + def self.browser_generated_types + ActiveSupport::Deprecation.warn "Mime::Type.browser_generated_types is deprecated and will be removed in Rails 4.1" + @@browser_generated_types + end + def html? @@html_types.include?(to_sym) || @string =~ /html/ end diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index db4da6f9c8..27ba57ff58 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -364,9 +364,9 @@ module ActionView # # * <tt>:alt</tt> - If no alt text is given, the file name part of the # +source+ is used (capitalized and without the extension) - # * <tt>:size</tt> - Supplied as "{Width}x{Height}", so "30x45" becomes - # width="30" and height="45". <tt>:size</tt> will be ignored if the - # value is not in the correct format. + # * <tt>:size</tt> - Supplied as "{Width}x{Height}" or "{Number}", so "30x45" becomes + # width="30" and height="45", and "50" becomes width="50" and height="50". + # <tt>:size</tt> will be ignored if the value is not in the correct format. # # image_tag("icon") # # => <img src="/assets/icon" alt="Icon" /> @@ -374,7 +374,7 @@ module ActionView # # => <img src="/assets/icon.png" alt="Icon" /> # image_tag("icon.png", :size => "16x10", :alt => "Edit Entry") # # => <img src="/assets/icon.png" width="16" height="10" alt="Edit Entry" /> - # image_tag("/icons/icon.gif", :size => "16x16") + # image_tag("/icons/icon.gif", :size => "16") # # => <img src="/icons/icon.gif" width="16" height="16" alt="Icon" /> # image_tag("/icons/icon.gif", :height => '32', :width => '32') # # => <img alt="Icon" height="32" src="/icons/icon.gif" width="32" /> @@ -390,7 +390,8 @@ module ActionView end if size = options.delete(:size) - options[:width], options[:height] = size.split("x") if size =~ %r{^\d+x\d+$} + options[:width], options[:height] = size.split("x") if size =~ %r{\A\d+x\d+\z} + options[:width] = options[:height] = size if size =~ %r{\A\d+\z} end tag("img", options) diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb index 3e83f3d4fa..e2a9ba782d 100644 --- a/actionpack/test/dispatch/mime_type_test.rb +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -185,9 +185,11 @@ class MimeTypeTest < ActiveSupport::TestCase all_types.uniq! # Remove custom Mime::Type instances set in other tests, like Mime::GIF and Mime::IPHONE all_types.delete_if { |type| !Mime.const_defined?(type.upcase) } - verified, unverified = all_types.partition { |type| Mime::Type.browser_generated_types.include? type } - assert verified.each { |type| assert Mime.const_get(type.upcase).verify_request?, "Verifiable Mime Type is not verified: #{type.inspect}" } - assert unverified.each { |type| assert !Mime.const_get(type.upcase).verify_request?, "Nonverifiable Mime Type is verified: #{type.inspect}" } + assert_deprecated do + verified, unverified = all_types.partition { |type| Mime::Type.browser_generated_types.include? type } + assert verified.each { |type| assert Mime.const_get(type.upcase).verify_request?, "Verifiable Mime Type is not verified: #{type.inspect}" } + assert unverified.each { |type| assert !Mime.const_get(type.upcase).verify_request?, "Nonverifiable Mime Type is verified: #{type.inspect}" } + end end test "references gives preference to symbols before strings" do diff --git a/actionpack/test/dispatch/rack_test.rb b/actionpack/test/dispatch/rack_test.rb index 698f980296..6d239d0a0c 100644 --- a/actionpack/test/dispatch/rack_test.rb +++ b/actionpack/test/dispatch/rack_test.rb @@ -176,13 +176,17 @@ end class RackRequestContentTypeTest < BaseRackTest test "html content type verification" do - @request.env['CONTENT_TYPE'] = Mime::HTML.to_s - assert @request.content_mime_type.verify_request? + assert_deprecated do + @request.env['CONTENT_TYPE'] = Mime::HTML.to_s + assert @request.content_mime_type.verify_request? + end end test "xml content type verification" do - @request.env['CONTENT_TYPE'] = Mime::XML.to_s - assert !@request.content_mime_type.verify_request? + assert_deprecated do + @request.env['CONTENT_TYPE'] = Mime::XML.to_s + assert !@request.content_mime_type.verify_request? + end end end diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb index 25d85c47c7..a04694714d 100644 --- a/actionpack/test/template/asset_tag_helper_test.rb +++ b/actionpack/test/template/asset_tag_helper_test.rb @@ -192,9 +192,9 @@ class AssetTagHelperTest < ActionView::TestCase ImageLinkToTag = { %(image_tag("xml.png")) => %(<img alt="Xml" src="/images/xml.png" />), %(image_tag("rss.gif", :alt => "rss syndication")) => %(<img alt="rss syndication" src="/images/rss.gif" />), + %(image_tag("gold.png", :size => "20")) => %(<img alt="Gold" height="20" src="/images/gold.png" width="20" />), %(image_tag("gold.png", :size => "45x70")) => %(<img alt="Gold" height="70" src="/images/gold.png" width="45" />), %(image_tag("gold.png", "size" => "45x70")) => %(<img alt="Gold" height="70" src="/images/gold.png" width="45" />), - %(image_tag("error.png", "size" => "45")) => %(<img alt="Error" src="/images/error.png" />), %(image_tag("error.png", "size" => "45 x 70")) => %(<img alt="Error" src="/images/error.png" />), %(image_tag("error.png", "size" => "x")) => %(<img alt="Error" src="/images/error.png" />), %(image_tag("google.com.png")) => %(<img alt="Google.com" src="/images/google.com.png" />), diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb index 495f0cde59..ba75c8be41 100644 --- a/activerecord/lib/active_record/associations/association.rb +++ b/activerecord/lib/active_record/associations/association.rb @@ -154,11 +154,8 @@ module ActiveRecord # We can't dump @reflection since it contains the scope proc def marshal_dump - reflection = @reflection - @reflection = nil - - ivars = instance_variables.map { |name| [name, instance_variable_get(name)] } - [reflection.name, ivars] + ivars = (instance_variables - [:@reflection]).map { |name| [name, instance_variable_get(name)] } + [@reflection.name, ivars] end def marshal_load(data) diff --git a/activerecord/test/cases/associations/extension_test.rb b/activerecord/test/cases/associations/extension_test.rb index bd5a426ca8..da767a2a7e 100644 --- a/activerecord/test/cases/associations/extension_test.rb +++ b/activerecord/test/cases/associations/extension_test.rb @@ -40,9 +40,12 @@ class AssociationsExtensionsTest < ActiveRecord::TestCase assert_equal projects(:action_controller), david.projects.find_most_recent marshalled = Marshal.dump(david) - david = Marshal.load(marshalled) - assert_equal projects(:action_controller), david.projects.find_most_recent + # Marshaling an association shouldn't make it unusable by wiping its reflection. + assert_not_nil david.association(:projects).reflection + + david_too = Marshal.load(marshalled) + assert_equal projects(:action_controller), david_too.projects.find_most_recent end def test_marshalling_named_extensions diff --git a/activerecord/test/cases/transaction_isolation_test.rb b/activerecord/test/cases/transaction_isolation_test.rb index 1e34f93d8f..a396da6645 100644 --- a/activerecord/test/cases/transaction_isolation_test.rb +++ b/activerecord/test/cases/transaction_isolation_test.rb @@ -44,6 +44,9 @@ class TransactionIsolationTest < ActiveRecord::TestCase # specifies what must not happen at a certain level, not what must happen. At # the read uncommitted level, there is nothing that must not happen. test "read uncommitted" do + unless ActiveRecord::Base.connection.transaction_isolation_levels.include?(:read_uncommitted) + skip "database does not support read uncommitted isolation level" + end Tag.transaction(isolation: :read_uncommitted) do assert_equal 0, Tag.count Tag2.create @@ -67,6 +70,9 @@ class TransactionIsolationTest < ActiveRecord::TestCase # We are testing that a nonrepeatable read does not happen test "repeatable read" do + unless ActiveRecord::Base.connection.transaction_isolation_levels.include?(:repeatable_read) + skip "database does not support repeatable read isolation level" + end tag = Tag.create(name: 'jon') Tag.transaction(isolation: :repeatable_read) do diff --git a/guides/source/security.md b/guides/source/security.md index 3a6a894695..0186386059 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -375,18 +375,25 @@ The common admin interface works like this: it's located at www.example.com/admi Mass Assignment --------------- -WARNING: _Without any precautions `Model.new(params[:model]`) allows attackers to set any database column's value._ +WARNING: _Without any precautions `Model.new(params[:model]`) allows attackers to set +any database column's value._ -The mass-assignment feature may become a problem, as it allows an attacker to set any model's attributes by manipulating the hash passed to a model's `new()` method: +The mass-assignment feature may become a problem, as it allows an attacker to set +any model's attributes by manipulating the hash passed to a model's `new()` method: ```ruby def signup - params[:user] # => {:name => “ow3ned”, :admin => true} + params[:user] # => {:name=>"ow3ned", :admin=>true} @user = User.new(params[:user]) end ``` -Mass-assignment saves you much work, because you don't have to set each value individually. Simply pass a hash to the `new` method, or `assign_attributes=` a hash value, to set the model's attributes to the values in the hash. The problem is that it is often used in conjunction with the parameters (params) hash available in the controller, which may be manipulated by an attacker. He may do so by changing the URL like this: +Mass-assignment saves you much work, because you don't have to set each value +individually. Simply pass a hash to the `new` method, or `assign_attributes=` +a hash value, to set the model's attributes to the values in the hash. The +problem is that it is often used in conjunction with the parameters (params) +hash available in the controller, which may be manipulated by an attacker. +He may do so by changing the URL like this: ``` http://www.example.com/user/signup?user[name]=ow3ned&user[admin]=1 @@ -395,12 +402,19 @@ http://www.example.com/user/signup?user[name]=ow3ned&user[admin]=1 This will set the following parameters in the controller: ```ruby -params[:user] # => {:name => “ow3ned”, :admin => true} +params[:user] # => {:name=>"ow3ned", :admin=>true} ``` -So if you create a new user using mass-assignment, it may be too easy to become an administrator. +So if you create a new user using mass-assignment, it may be too easy to become +an administrator. -Note that this vulnerability is not restricted to database columns. Any setter method, unless explicitly protected, is accessible via the `attributes=` method. In fact, this vulnerability is extended even further with the introduction of nested mass assignment (and nested object forms) in Rails 2.3. The `accepts_nested_attributes_for` declaration provides us the ability to extend mass assignment to model associations (`has_many`, `has_one`, `has_and_belongs_to_many`). For example: +Note that this vulnerability is not restricted to database columns. Any setter +method, unless explicitly protected, is accessible via the `attributes=` method. +In fact, this vulnerability is extended even further with the introduction of +nested mass assignment (and nested object forms) in Rails 2.3. The +`accepts_nested_attributes_for` declaration provides us the ability to extend +mass assignment to model associations (`has_many`, `has_one`, +`has_and_belongs_to_many`). For example: ```ruby class Person < ActiveRecord::Base @@ -414,77 +428,84 @@ Note that this vulnerability is not restricted to database columns. Any setter m end ``` -As a result, the vulnerability is extended beyond simply exposing column assignment, allowing attackers the ability to create entirely new records in referenced tables (children in this case). +As a result, the vulnerability is extended beyond simply exposing column +assignment, allowing attackers the ability to create entirely new records +in referenced tables (children in this case). ### Countermeasures -To avoid this, Rails provides two class methods in your Active Record class to control access to your attributes. The `attr_protected` method takes a list of attributes that will not be accessible for mass-assignment. For example: +To avoid this, Rails provides an interface for protecting attributes from +end-user assignment called Strong Parameters. This makes Action Controller +parameters forbidden until they have been whitelisted, so you will have to +make a conscious choice about which attributes to allow for mass assignment +and thus prevent accidentally exposing that which shouldn’t be exposed. -```ruby -attr_protected :admin -``` - -`attr_protected` also optionally takes a role option using :as which allows you to define multiple mass-assignment groupings. If no role is defined then attributes will be added to the :default role. +NOTE. Before Strong Parameters arrived, mass-assignment protection was a +model's task provided by Active Model. This has been extracted to the +[ProtectedAttributes](https://github.com/rails/protected_attributes) +gem. In order to use `attr_accessible` and `attr_protected` helpers in +your models, you should add `protected_attributes` to your Gemfile. -```ruby -attr_protected :last_login, :as => :admin -``` +Why we moved mass-assignment protection out of the model and into +the controller? The whole point of the controller is to control the +flow between user and application, including authentication, authorization, +and, as part of that, access control. -A much better way, because it follows the whitelist-principle, is the `attr_accessible` method. It is the exact opposite of `attr_protected`, because _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: +Strong Parameters provides two methods to the `params` hash to control +access to your attributes: `require` and `permit`. The former is used +to mark parameters as required and the latter limits which attributes +should be allowed for mass updating using the slice pattern. For example: ```ruby -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: +def signup + params[:user] + # => {:name=>"ow3ned", :admin=>true} + permitted_params = params.require(:user).permit(:name) + # => {:name=>"ow3ned"} -```ruby -params[:user] # => {:name => "ow3ned", :admin => true} -@user = User.new(params[:user]) -@user.admin # => false # not mass-assigned -@user.admin = true -@user.admin # => true + @user = User.new(permitted_params) +end ``` -When assigning attributes in Active Record using `attributes=` the :default role will be used. To assign attributes using different roles you should use `assign_attributes` which accepts an optional :as options parameter. If no :as option is provided then the :default role will be used. You can also bypass mass-assignment security by using the `:without_protection` option. Here is an example: +In the example above, `require` is checking whether a `user` key is present or not +in the parameters, if it's not present, it'll raise an `ActionController::MissingParameter` +exception, which will be caught by `ActionController::Base` and turned into a +400 Bad Request reply. Then `permit` whitelists the attributes that should be +allowed for mass assignment. -```ruby -@user = User.new +A good pattern to encapsulate the permissible parameters is to use a private method +since you'll be able to reuse the same permit list between different actions. -@user.assign_attributes({ :name => 'Josh', :is_admin => true }) -@user.name # => Josh -@user.is_admin # => false +```ruby +def signup + @user = User.new(user_params) + # ... +end -@user.assign_attributes({ :name => 'Josh', :is_admin => true }, :as => :admin) -@user.name # => Josh -@user.is_admin # => true +def update + @user = User.find(params[:id] + @user.update_attributes!(user_params) + # ... +end -@user.assign_attributes({ :name => 'Josh', :is_admin => true }, :without_protection => true) -@user.name # => Josh -@user.is_admin # => true +private + def user_params + params.require(:user).permit(:name) + end ``` -In a similar way, `new`, `create`, `create!`, `update_attributes`, and `update_attributes!` methods all respect mass-assignment security and accept either `:as` or `:without_protection` options. For example: +Also, you can specialize this method with per-user checking of permissible +attributes. ```ruby -@user = User.new({ :name => 'Sebastian', :is_admin => true }, :as => :admin) -@user.name # => Sebastian -@user.is_admin # => true +def user_params + filters = [:name] + filters << :admin if current_user.try(:admin?) -@user = User.create({ :name => 'Sebastian', :is_admin => true }, :without_protection => true) -@user.name # => Sebastian -@user.is_admin # => true -``` - -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: - -```ruby -config.active_record.whitelist_attributes = true + params.require(:user).permit(*filters) +end ``` -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. - User Management --------------- @@ -669,7 +690,7 @@ A blacklist can be a list of bad e-mail addresses, non-public actions or bad HTM * Allow <strong> instead of removing <script> against Cross-Site Scripting (XSS). See below for details. * Don't try to correct user input by blacklists: * This will make the attack work: "<sc<script>ript>".gsub("<script>", "") - * But reject malformed input + * But reject malformed input Whitelists are also a good approach against the human factor of forgetting something in the blacklist. @@ -1059,7 +1080,7 @@ config.action_dispatch.default_headers.clear Here is the list of common headers: * X-Frame-Options -_'SAMEORIGIN' in Rails by default_ - allow framing on same domain. Set it to 'DENY' to deny framing at all or 'ALLOWALL' if you want to allow framing for all website. +_'SAMEORIGIN' in Rails by default_ - allow framing on same domain. Set it to 'DENY' to deny framing at all or 'ALLOWALL' if you want to allow framing for all website. * X-XSS-Protection _'1; mode=block' in Rails by default_ - use XSS Auditor and block page if XSS attack is detected. Set it to '0;' if you want to switch XSS Auditor off(useful if response contents scripts from request parameters) * X-Content-Type-Options diff --git a/railties/lib/rails/rack/logger.rb b/railties/lib/rails/rack/logger.rb index 89de10c83d..9ff94e74b3 100644 --- a/railties/lib/rails/rack/logger.rb +++ b/railties/lib/rails/rack/logger.rb @@ -10,7 +10,7 @@ module Rails end def call(env) - if @tags + if @tags && Rails.logger.respond_to?(:tagged) Rails.logger.tagged(compute_tags(env)) { call_app(env) } else call_app(env) |