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
Enable :except option to :protect_from_csrf. #1539
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -339,11 +339,28 @@ def setup_csrf_protection(builder) | |
check_csrf_protection_dependency | ||
|
||
if protect_from_csrf? | ||
if protect_from_csrf.is_a?(Hash) | ||
except = Array(protect_from_csrf[:except]) | ||
if !except.empty? | ||
except.each{|except_path| exception_router.before(except_path, &ignore_csrf_protection) } | ||
builder.use exception_router | ||
end | ||
end | ||
builder.use(Rack::Protection::AuthenticityToken, | ||
options_for_csrf_protection_setup) | ||
end | ||
end | ||
|
||
# the sinatra app for routes to disable the csrf protection. | ||
def exception_router | ||
@exception_router ||= Class.new(Sinatra::Base) | ||
end | ||
|
||
# returns a proc to avoid csrf protection. | ||
def ignore_csrf_protection | ||
Proc.new { env['HTTP_X_CSRF_TOKEN'] = session[:csrf] = SecureRandom.hex(32) } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please check whether I am reading this right: This randomly changes the CSRF value when hitting an excepted path. Consider the following case:
Also, this filter even runs on safe urls, like GET requests. Bypassing the authenticity token middleware instead of hacking through it seems to be a better option. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let me make sure I understand you correctly. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess it could be just There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ujifgc That would break if no CSRF token was ever given to the user or there is no session middleware. No, I mean that we should not invoke CSRF protection at all when no CSRF is wanted. Currently, the implementation basically fakes a successful request. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ujifgc Like it. def ignore_csrf_protection
Proc.new do
env['HTTP_X_CSRF_TOKEN'] = session[:csrf] if request.post?
end
end There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @skade do you know a way not to invoke Rack::Protection::AuthenticityToken if it's already used in the builder? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ujifgc Skipping isn't easy with builder alone, but a pattern like this works: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @skade yes, it makes sense. We could subclass AuthenticityToken, upgrade it with url exceptions and use it instead of the original. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the long run: Rack::Builder shows it's age, especially with things like that :(. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, makes sense. |
||
end | ||
|
||
# returns the options used in the builder for csrf protection setup | ||
def options_for_csrf_protection_setup | ||
options = { :logger => logger } | ||
|
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 am late to the party, but
if !except.empty?
isunless except.empty
.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.
Oops, Thank you. I'll fix it.
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.
BTW, @namusyaka what's your primary programming language?
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 love JavaScript and Ruby.