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
Optionally allow ActionCable requests from the same host as origin #26568
Conversation
Thanks for the pull request, and welcome! The Rails team is excited to review your changes, and you should hear from @rafaelfranca (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. This repository is being automatically checked for code quality issues using Code Climate. You can see results for this analysis in the PR status below. Newly introduced issues should be fixed before a Pull Request is considered ready to review. Please see the contribution instructions for more information. |
FYI @matthewd |
cafa208
to
92b8535
Compare
I think we can enable this always, without needing a config option. The point of the origin check is to protect against cross-origin websocket connections, which could give privileged access because of a cookie; if the origin matches the request hostname, then the originating page already had access to any such cookie... right? cc @rails/security |
if Array(server.config.allowed_request_origins).any? { |allowed_origin| allowed_origin === env["HTTP_ORIGIN"] } | ||
true | ||
elsif server.config.allow_same_origin_as_host && env["HTTP_ORIGIN"].start_with?("#{proto}://#{env['HTTP_HOST']}") |
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.
Origin doesn't have a suffix, so this should be an ==
comparison.
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.
@matthewd fixed
92b8535
to
cd9d8dd
Compare
@server.config.allow_same_origin_as_host = true | ||
assert_origin_allowed "http://#{HOST}" | ||
assert_origin_not_allowed "http://hax.com" | ||
assert_origin_not_allowed "http://rails.co.uk/" |
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 the allowed one should be a literal string.. probably. And this last line needs to lose the trailing /
to have much meaning.
Also, is this test leaving the config option set? The teardown makes sure to reset the others.
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.
@matthewd both fixed
cd9d8dd
to
92c9dac
Compare
When the `allow_same_origin_as_host` is set to `true`, the request forgery protection permits `HTTP_ORIGIN` values starting with the corresponding `proto://` prefix followed by `HTTP_HOST`. This way it is not required to specify the list of allowed URLs.
92c9dac
to
268c340
Compare
That protects against same-origin cookies (barring DNS rebinding which would poke through in any case) conferring auth, but not against accepting the connection in the first place, affecting apps with non-authenticated conns and (marginally) increasing DoS risk. |
Even DNS rebinding is okay, because that only gets the attacker access to cookies belonging to their rebound name, not the "real" one. If the code making the request came from the same origin as the hostname you've been supplied (here, a DNS rebinding disclaimer is indeed required), then regardless of whether the hostname is the real one or an attacker-owned fake pointing at your IP, it's your code. AIUI, the only real exposure here is if the connection-initiating-party can fake one or both of those headers (giving a host header that didn't resolve to this server, or an origin that isn't true)... and at that point, you're dealing with something other than a browser, which would be just as capable of claiming whatever origin you're explicitly checking for. |
Optionally allow ActionCable requests from the same host as origin
Defaulted to on in dae4044; I decided to stop short of removing the option altogether. |
Optionally allow ActionCable requests from the same host as origin
WebSocket always defers the decision to the server, because it didn't have to deal with legacy compatibility... but the same-origin policy is still a reasonable default. Origin checks do not protect against a directly connecting attacker -- they can lie about their host, but can also lie about their origin. Origin checks protect against a connection from 3rd-party controlled script in a context where a victim browser's cookies will be passed along. And if an attacker has breached that protection, they've already compromised the HTTP session, so treating the WebSocket connection in the same way seems reasonable. In case this logic proves incorrect (or anyone just wants to be more paranoid), we retain a config option to disable it.
Summary
When the
allow_same_origin_as_host
is set totrue
, the requestforgery protection permits
HTTP_ORIGIN
values starting with thecorresponding
proto://
prefix followed byHTTP_HOST
. This wayit is not required to specify the list of allowed URLs.
Other Information
https://groups.google.com/forum/?fromgroups#!topic/rubyonrails-core/4U5pKIgtJFU