New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default protect from forgery #29742

Merged
merged 2 commits into from Jul 10, 2017

Conversation

Projects
None yet
8 participants
@lugray
Contributor

lugray commented Jul 10, 2017

Summary

Fixes #29193.

Protect from forgery by default: Rather than protecting from forgery in the generated ApplicationController, add it to ActionController::Base by config. 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.

Also adds ActionController::Base.skip_forgery_protection as a wrapper to skip_before_action :verify_authenticity_token for disabling forgery protection.

@lugray

This comment has been minimized.

Show comment
Hide comment
Contributor

lugray commented Jul 10, 2017

Show outdated Hide outdated 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) do

This comment has been minimized.

@rafaelfranca

rafaelfranca Jul 10, 2017

Member

This is also going to run for ActionController::Api, so it is better to use on_load(:action_controller_base here. That way we can do:

ActiveSupport.on_load(:action_controller_base) do
  if app.config.action_controller.default_protect_from_forgery
    protect_from_forgery with: :exception
  end
end
@rafaelfranca

rafaelfranca Jul 10, 2017

Member

This is also going to run for ActionController::Api, so it is better to use on_load(:action_controller_base here. That way we can do:

ActiveSupport.on_load(:action_controller_base) do
  if app.config.action_controller.default_protect_from_forgery
    protect_from_forgery with: :exception
  end
end
@@ -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

This comment has been minimized.

@rafaelfranca

rafaelfranca Jul 10, 2017

Member

We need to add this config to the configurations.md guide.

@rafaelfranca

rafaelfranca Jul 10, 2017

Member

We need to add this config to the configurations.md guide.

This comment has been minimized.

@lugray

lugray Jul 10, 2017

Contributor

Done.

@lugray

lugray Jul 10, 2017

Contributor

Done.

Show outdated Hide outdated actionpack/lib/action_controller/metal/request_forgery_protection.rb
#
# skip_before_action :verify_authenticity_token
#
# See skip_before_action for allowed options.

This comment has been minimized.

@Edouard-chin

Edouard-chin Jul 10, 2017

Contributor

Small nitpicks, might use plus sign +skip_before_action+ for rdoc

@Edouard-chin

Edouard-chin Jul 10, 2017

Contributor

Small nitpicks, might use plus sign +skip_before_action+ for rdoc

This comment has been minimized.

@lugray

lugray Jul 10, 2017

Contributor

Thanks!

@lugray

lugray Jul 10, 2017

Contributor

Thanks!

@rafaelfranca

Last thing. Could you add a CHANGELOG entry?

Show outdated Hide outdated railties/test/application/configuration_test.rb
test "config.action_controller.default_protect_from_forgery is true by default on production" do
app "production"
ActionController::Base.object_id # force lazy load hooks to run

This comment has been minimized.

@eugeneius

eugeneius Jul 10, 2017

Member

This isn't necessary, since referencing ActionController::Base on the next line will run the lazy load hooks. It's only needed when testing ActionController::Parameters options, as loading that class won't trigger the hooks.

@eugeneius

eugeneius Jul 10, 2017

Member

This isn't necessary, since referencing ActionController::Base on the next line will run the lazy load hooks. It's only needed when testing ActionController::Parameters options, as loading that class won't trigger the hooks.

Show outdated Hide outdated railties/test/application/configuration_test.rb
@@ -1209,6 +1209,15 @@ def create
assert_equal false, ActionController::Parameters.action_on_unpermitted_parameters
end
test "config.action_controller.default_protect_from_forgery is true by default on production" do

This comment has been minimized.

@eugeneius

eugeneius Jul 10, 2017

Member

The behaviour here doesn't depend on the environment, so I'd ✂️ "on production" from the test name.

@eugeneius

eugeneius Jul 10, 2017

Member

The behaviour here doesn't depend on the environment, so I'd ✂️ "on production" from the test name.

Show outdated Hide outdated railties/test/application/configuration_test.rb
@@ -1209,6 +1209,15 @@ def create
assert_equal false, ActionController::Parameters.action_on_unpermitted_parameters
end
test "config.action_controller.default_protect_from_forgery is true by default on production" do
app "production"

This comment has been minimized.

@eugeneius

eugeneius Jul 10, 2017

Member

The rest of the tests in this file set this as "development" when the behaviour doesn't depend on the particular environment; we should probably do the same here for consistency.

@eugeneius

eugeneius Jul 10, 2017

Member

The rest of the tests in this file set this as "development" when the behaviour doesn't depend on the particular environment; we should probably do the same here for consistency.

Show outdated Hide outdated 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.

This comment has been minimized.

@eugeneius

eugeneius Jul 10, 2017

Member

ActionController:Base -> ActionController::Base (with backticks 😊)

@eugeneius

eugeneius Jul 10, 2017

Member

ActionController:Base -> ActionController::Base (with backticks 😊)

Show outdated Hide outdated 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

This comment has been minimized.

@eugeneius

eugeneius Jul 10, 2017

Member

This line needs a full stop at the end.

@eugeneius

eugeneius Jul 10, 2017

Member

This line needs a full stop at the end.

Show outdated Hide outdated actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -128,6 +132,15 @@ def protect_from_forgery(options = {})
append_after_action :verify_same_origin_request
end
# Turn off request forgery protection. This is a wrapper for

This comment has been minimized.

@eugeneius

eugeneius Jul 10, 2017

Member

I think there should be a colon here:

This is a wrapper for:

@eugeneius

eugeneius Jul 10, 2017

Member

I think there should be a colon here:

This is a wrapper for:

@lugray

This comment has been minimized.

Show comment
Hide comment
@lugray

lugray Jul 10, 2017

Contributor

Thanks @eugeneius, updated as per your review.

Contributor

lugray commented Jul 10, 2017

Thanks @eugeneius, updated as per your review.

@eugeneius

This comment has been minimized.

Show comment
Hide comment
@eugeneius

eugeneius Jul 10, 2017

Member

This looks great! 👏

My only remaining question is whether there should be an entry in new_framework_defaults_5_2.rb for this, so that upgraded apps can opt-in to the new behaviour if they want it. My understanding of that file is that it should mirror the options from Rails::Application::Configuration#load_defaults.

Member

eugeneius commented Jul 10, 2017

This looks great! 👏

My only remaining question is whether there should be an entry in new_framework_defaults_5_2.rb for this, so that upgraded apps can opt-in to the new behaviour if they want it. My understanding of that file is that it should mirror the options from Rails::Application::Configuration#load_defaults.

lugray added some commits Jul 10, 2017

Protect from forgery by default
Rather than protecting from forgery in the generated
ApplicationController, add it to ActionController::Base by config. 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.
Add ActionController::Base.skip_forgery_protection
Since we now default to `protect_from_forgery with: :exception`,
provide a wrapper to `skip_before_action :verify_authenticity_token`
for disabling forgery protection.
@lugray

This comment has been minimized.

Show comment
Hide comment
@lugray

lugray Jul 10, 2017

Contributor

@eugeneius That makes sense. I added to new_framework_defaults_5_2.rb.tt

Contributor

lugray commented Jul 10, 2017

@eugeneius That makes sense. I added to new_framework_defaults_5_2.rb.tt

@rafaelfranca rafaelfranca merged commit 48cb8b3 into rails:master Jul 10, 2017

1 of 2 checks passed

continuous-integration/travis-ci/pr The Travis CI build is in progress
Details
codeclimate All good!
Details

@lugray lugray deleted the lugray:default_protect_from_forgery branch Jul 10, 2017

# Add default protection from forgery to ActionController::Base instead of in
# ApplicationController.
# Rails.applocation.config.action_controller.default_protect_from_forgery = true

This comment has been minimized.

@UlrichThomasGabor

UlrichThomasGabor Jul 24, 2017

There is a typo applocation

@UlrichThomasGabor

UlrichThomasGabor Jul 24, 2017

There is a typo applocation

This comment has been minimized.

@lugray

lugray Jul 24, 2017

Contributor

Thanks, I'll get a fix up.

@lugray

lugray Jul 24, 2017

Contributor

Thanks, I'll get a fix up.

This comment has been minimized.

@lugray

lugray Jul 24, 2017

Contributor

Actually, it already got fixed in e01b240.

@lugray

lugray Jul 24, 2017

Contributor

Actually, it already got fixed in e01b240.

@wnm

This comment has been minimized.

Show comment
Hide comment
@wnm

wnm Jan 24, 2018

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.

@lugray don't older versions have it in ApplicationController, and the new default is there to move it to ActionController::Base so we can remove it from ApplicationController?

wnm commented Jan 24, 2018

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.

@lugray don't older versions have it in ApplicationController, and the new default is there to move it to ActionController::Base so we can remove it from ApplicationController?

@lugray

This comment has been minimized.

Show comment
Hide comment
@lugray

lugray Jan 24, 2018

Contributor

@wnm By default, older versions do have it in ApplicationController. The point I'm making is that the way to turn it off in older versions would have been to remove the line from the generated ApplicationController. If someone has actively removed it because they don't want it, upgrading should not change the behavior. But new applications will get the 5.2 defaults, which set it to true. If you're upgrading an older version of rails, and you want to remove it from ApplicationController, you'll need to change the configuration you use, since you won't have the 5.2 defaults.

Contributor

lugray commented Jan 24, 2018

@wnm By default, older versions do have it in ApplicationController. The point I'm making is that the way to turn it off in older versions would have been to remove the line from the generated ApplicationController. If someone has actively removed it because they don't want it, upgrading should not change the behavior. But new applications will get the 5.2 defaults, which set it to true. If you're upgrading an older version of rails, and you want to remove it from ApplicationController, you'll need to change the configuration you use, since you won't have the 5.2 defaults.

@wnm

This comment has been minimized.

Show comment
Hide comment
@wnm

wnm Jan 24, 2018

@lugray ah I see... totally makes sense. thanks for the quick response!!

wnm commented Jan 24, 2018

@lugray ah I see... totally makes sense. thanks for the quick response!!

@octavpo

This comment has been minimized.

Show comment
Hide comment
@octavpo

octavpo Apr 24, 2018

I think it would be better if the default_protect_from_forgery config could take the :with parameter as a value.

There's also an inconsistency in approach that if you use default_protect_from_forgery = true in config it defaults to :exception, while if you use protect_from_forgery with no parameters in the controller it defaults to :null_session.

octavpo commented Apr 24, 2018

I think it would be better if the default_protect_from_forgery config could take the :with parameter as a value.

There's also an inconsistency in approach that if you use default_protect_from_forgery = true in config it defaults to :exception, while if you use protect_from_forgery with no parameters in the controller it defaults to :null_session.

@collimarco

This comment has been minimized.

Show comment
Hide comment
@collimarco

collimarco Jun 12, 2018

There's also an inconsistency in approach that if you use default_protect_from_forgery = true in config it defaults to :exception, while if you use protect_from_forgery with no parameters in the controller it defaults to :null_session.

I totally agree! It is not clear from the docs that the default behavior is :exception.

There's also an inconsistency in approach that if you use default_protect_from_forgery = true in config it defaults to :exception, while if you use protect_from_forgery with no parameters in the controller it defaults to :null_session.

I totally agree! It is not clear from the docs that the default behavior is :exception.

ceritium added a commit to ceritium/featurer_web that referenced this pull request Jul 5, 2018

Make it works with CSRF token
Rails 5.1 has the CSRF protection disabled by default but rails 5.2 enable it
again. rails/rails#29742

- Remove the fancy ajax delete.
- Use jquery_ujs for the delete action (it must be included by the host app at the moment).
- Add `csrf_meta_tags` on the layout.

jkeck added a commit to sul-dlss/vatican_exhibits that referenced this pull request Jul 21, 2018

Protect from forgery by default
Rails 5.2 added this behavior in rails/rails#29742 however it is false by default for backwards compatibility.

jkeck added a commit to sul-dlss/vatican_exhibits that referenced this pull request Jul 21, 2018

Protect from forgery by default
Rails 5.2 added this behavior in rails/rails#29742

camillevilla added a commit to sul-dlss/vatican_exhibits that referenced this pull request Jul 23, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment