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
Add prepend option to protect_from_forgery. #18334
Conversation
@@ -87,6 +87,7 @@ module ClassMethods | |||
# | |||
# * <tt>:only/:except</tt> - Passed to the <tt>before_action</tt> call. Set which actions are verified. | |||
# * <tt>:if/:unless</tt> - Passed to the <tt>before_action</tt> call. Set when actions are verified. | |||
# * <tt>:prepend</tt> - ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think Passed to the <tt>before_action</tt> call.
should be skipped here since it is not commonly used option. Any idea how to describe it here in few words?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:prepend - By default, the verification of the authentication token is added to the front of the callback chain. If you need to make the verification depend on other callbacks, like authentication methods (say cookies vs oauth), this might not work for you. Pass prepend: false to just add the verification callback in the position of the protect_from_forgery call. This means any callbacks added before are run first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The two first options should be described in terms of before_action. That’s all internal stuff. Maybe just:
only/except - Only apply forgery protection to a subset of actions. Like only: [ :create, :create_all ]
if/unless - Turn off the forgery protection entirely depending on the passed proc or method reference.
Also, needs to say “You can disable forgery protection” not just CRSF — since we also check same origin.
On Jan 4, 2015, at 5:46 PM, Josef Šimánek notifications@github.com wrote:
In actionpack/lib/action_controller/metal/request_forgery_protection.rb #18334 (diff):
@@ -87,6 +87,7 @@ module ClassMethods
#
# * :only/:except - Passed to the before_action call. Set which actions are verified.
# * :if/:unless - Passed to the before_action call. Set when actions are verified.
Thanks.# \* <tt>:prepend</tt> - ?
https://cloud.githubusercontent.com/assets/193936/5608460/edecd69a-9484-11e4-8602-431ce1246175.png
—
Reply to this email directly or view it on GitHub https://github.com/rails/rails/pull/18334/files#r22445355.
40fbd51
to
6790897
Compare
@@ -94,9 +99,11 @@ module ClassMethods | |||
# * <tt>:reset_session</tt> - Resets the session. | |||
# * <tt>:null_session</tt> - Provides an empty session during request but doesn't reset it completely. Used as default if <tt>:with</tt> option is not specified. | |||
def protect_from_forgery(options = {}) | |||
options.reverse_merge!(prepend: true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps not mutate options here passed by user?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And where? The idea behind this is to make prepend: true
default (to keep backwards compatibility), but be able to pass prepend: false
to before_action
when you need.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
options = options.reverse_merge(prepend: true)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense. Thanks @egilburg.
6790897
to
d44164c
Compare
d44164c
to
7d62d53
Compare
Did you want to do some more work on this, or should I merge as-is? |
I'm thinking about some test improvements (only code style), but it can be done later. Dou you think changelog note is needed here? |
I think this is fine. And yes, let's add a changelog entry describing the new option. |
7d62d53
to
2fce31f
Compare
I added some CHANGELOG note. Feel free to suggest me better text since I'm not english native speaker. |
Here's a full-fledged example for it:
|
Maybe it is good idea to mention this in guides also. Do you agree?
|
Yes, that'd be great.
|
If you add the description I gave to the changelog and rebase, we can merge this. Then we can follow up with a doc PR for the guides. |
2fce31f
to
f54a4a8
Compare
f54a4a8
to
0074bbb
Compare
@dhh done. |
…rgery Add prepend option to protect_from_forgery.
Actually, on second thoughts, @carlosantoniodasilva suggested that this should just be the default behavior, and I couldn't come up with a reason why that shouldn't be so. The protection just needs to run before the action is hit, so there shouldn't be any backwards incompatibility with changing from prepend to append. So let's just do that. You can still get the old behavior by adding |
OK, I'll edit this. |
@dhh could this introduce potential security vulnerability for users who happen to do some important (e.g. db destructive) step in a before filter? Arguably it's not great app design, but perhaps need make this a deprecated process rather than silent switch. |
Eugune, do you have any examples of that? Sounds pretty crazy.
|
As I said before you can use class ApplicationController < ActionController::Base
before_filter :update_something
protect_from_forgery
end I think that is the reason why it was prepended. I think it is ok to add option to skip prepending, but it should stay unchanged by default. |
Right, it’s technically possible to do that. It’s technically possible to do a lot of crazy shit. At some point you have to say “we’re not going to take on every possible ounce of crazy”. I’d like to see just one real example from this before going down another migration path for a possibly-maybe-probably-not.
|
@dhh no I don't, was just being a bit cautious since this is a security feature. |
Yup, it’s worth considering, and no fault for bringing it up. But I’d like more than a “I could possibly imagine” before we drive it that way. As with everything, we’ll spell out these changes in the upgrade document.
|
Per this comment rails#18334 (comment) we want `protect_from_forgery` to default to `prepend: false`. `protect_from_forgery` will now be insterted into the callback chain at the point it is called in your application. This is useful for cases where you want to `protect_from_forgery` after you perform required authentication callbacks or other callbacks that are required to run after forgery protection. If you want `protect_from_forgery` callbacks to always run first, regardless of position they are called in your application, then you can add `prepend: true` to your `protect_from_forgery` call. Example: ```ruby protect_from_forgery prepend: true ```
Per this comment #18334 (comment) we want `protect_from_forgery` to default to `prepend: false`. `protect_from_forgery` will now be insterted into the callback chain at the point it is called in your application. This is useful for cases where you want to `protect_from_forgery` after you perform required authentication callbacks or other callbacks that are required to run after forgery protection. If you want `protect_from_forgery` callbacks to always run first, regardless of position they are called in your application, then you can add `prepend: true` to your `protect_from_forgery` call. Example: ```ruby protect_from_forgery prepend: true ```
Suggested by @dhh in #18329 (comment).
This is first iteration. I try to refactor tests to keep it DRY'ed.
Closes #18329