diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index f8fd2403ef8bc22132df6b64fdfa834fa46916cc..59a7f12ac6cdad666e3fe051694948b4a6d6437a 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,3 +1,13 @@ +* Protect from forgery by default + + Rather than protecting from forgery in the generated ApplicationController, + add it to ActionController::Base depending on + `config.action_controller.default_protect_from_forgery`. This configuration + defaults to false to support older versions which have removed it from their + ApplicationController, but is set to true for Rails 5.2. + + *Lisa Ugray* + * Fallback `ActionController::Parameters#to_s` to `Hash#to_s`. *Kir Shatrov* diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb index 4468cbb2fc29307f470e479716df86fc2740af11..117dee221939665adb3166669aa047ba5261522b 100644 --- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb @@ -85,6 +85,10 @@ module RequestForgeryProtection config_accessor :per_form_csrf_tokens self.per_form_csrf_tokens = false + # Controls whether forgery protection is enabled by default. + config_accessor :default_protect_from_forgery + self.default_protect_from_forgery = false + helper_method :form_authenticity_token helper_method :protect_against_forgery? end diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index 31db7518f19bf3451d1b16794632274135ca7d78..1c1cd587328424cb9d3be0a853882ec96aa4d8fc 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -69,5 +69,13 @@ class Railtie < Rails::Railtie #:nodoc: config.compile_methods! if config.respond_to?(:compile_methods!) end end + + initializer "action_controller.request_forgery_protection" do |app| + ActiveSupport.on_load(:action_controller_base) do + if app.config.action_controller.default_protect_from_forgery + protect_from_forgery with: :exception + end + end + end end end diff --git a/guides/source/configuring.md b/guides/source/configuring.md index 21b3ca0efa5158e095556f84bfc07b441ad770b6..28ceef9740a92de28ee75ee093bb1bf3afdb1414 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -401,6 +401,8 @@ The schema dumper adds one additional configuration option: * `config.action_controller.per_form_csrf_tokens` configures whether CSRF tokens are only valid for the method/action they were generated for. +* `config.action_controller.default_protect_from_forgery` determines whether forgery protection is added on `ActionController:Base`. This is false by default, but enabled when loading defaults for Rails 5.2. + * `config.action_controller.relative_url_root` can be used to tell Rails that you are [deploying to a subdirectory](configuring.html#deploy-to-a-subdirectory-relative-url-root). The default is `ENV['RAILS_RELATIVE_URL_ROOT']`. * `config.action_controller.permit_all_parameters` sets all the parameters for mass assignment to be permitted by default. The default value is `false`. diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index 7e1359c42b3753fe2c3f052f4efaa3812bb89a8d..d403c4fa7c4ba958f9c8899060ea288ac015f377 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -96,6 +96,10 @@ def load_defaults(target_version) active_support.use_authenticated_message_encryption = true end + if respond_to?(:action_controller) + action_controller.default_protect_from_forgery = true + end + else raise "Unknown version #{target_version.to_s.inspect}" end diff --git a/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt index 413354186d4478dd098ede872423893996c625ed..185c0017f12682c434565dff3f5a54b6a8e8874a 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt @@ -1,5 +1,2 @@ class ApplicationController < ActionController::<%= options[:api] ? "API" : "Base" %> -<%- unless options[:api] -%> - protect_from_forgery with: :exception -<%- end -%> end diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_5_2.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_5_2.rb.tt index 3809936f9f13060348955688a2f986bffd4e4a90..e8f5f964ed2b32be33c97add269d08187cedf647 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_5_2.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_5_2.rb.tt @@ -17,3 +17,7 @@ # Use AES-256-GCM authenticated encryption as default cipher for encrypting messages # instead of AES-256-CBC, when use_authenticated_message_encryption is set to true. # Rails.application.config.active_support.use_authenticated_message_encryption = true + +# Add default protection from forgery to ActionController::Base instead of in +# ApplicationController. +# Rails.applocation.config.action_controller.default_protect_from_forgery = true diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 983ea5c3e61acc10ad3312b66c80d3fa7d774cee..6c0c0873317cefec53aab5c2c3a44e0865fef11d 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -1209,6 +1209,13 @@ def create assert_equal false, ActionController::Parameters.action_on_unpermitted_parameters end + test "config.action_controller.default_protect_from_forgery is true by default" do + app "development" + + assert_equal true, ActionController::Base.default_protect_from_forgery + assert_includes ActionController::Base.__callbacks[:process_action].map(&:filter), :verify_authenticity_token + end + test "config.action_controller.permit_all_parameters can be configured in an initializer" do app_file "config/initializers/permit_all_parameters.rb", <<-RUBY Rails.application.config.action_controller.permit_all_parameters = true diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index 5ae6ea925fc426d3525f5c219842644d72dbb717..134106812df889a254b6f7d723fef16b789908cf 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -117,7 +117,7 @@ def test_should_not_eager_load_model_for_rake end def test_code_statistics_sanity - assert_match "Code LOC: 26 Test LOC: 0 Code to Test Ratio: 1:0.0", + assert_match "Code LOC: 25 Test LOC: 0 Code to Test Ratio: 1:0.0", Dir.chdir(app_path) { `bin/rails stats` } end