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
ActionCable: Same origin match against X-FORWARDED-HOST when proxying #34716
Conversation
When using `allow_same_origin_as_host` with a reverse proxy the `HOST` header is set to the proxy host which will cause the CSRF protection to forbid the request. Each time a request hits a reverse proxy, it updated the `HOST` header and also prepends the host from the previous request to the `X-FORWARDED-FOR` header. When the request finally hits the server where ActionCable is running, the first host in the header will be the right one for us. I am proposing to change my original idea introduced in 268c340 to test against the first element of this header when it is set.
c4592e6
to
bd25e94
Compare
Hmmm... my first reaction is that I'm not sure this is safe, because we can't be sure the upstream will set/clear that header, even if we establish that the upstream is itself trusted. (The latter is where RFC 7239 comes in, but until it's more widely adopted we have the same issue that we can't assume it itself didn't come from somewhere unknown.) Looking back to my reasoning in #26568 (comment), however, I think that might suggest this is still safe: a victim browser pointing at an attacker's DNS name won't send cookies that belong to the site's real DNS name, regardless of whether they're talking directly to our server or to an attacker-controlled header-modifying proxy. The danger is exclusively that an attacker can cause a victim's browser to connect to our server, using our DNS name, from an attacker-controlled Origin -- and barring [out-of-scope] DNS hijacking, I think we're still covered. (Assuming it's not possible for JS to specify a header value. I think the trust issues above do still preclude our relying on that header for other uses where knowing our hostname is actually important... we just might have weaker requirements in this particular instance. Incidentally, I think most reverse-proxy configurations side-step this sort of problem by having the proxy pass along the original |
@matthewd this depends on the |
@matthewd when we mentioned you've mentioned there's an issue with this, can you please explain it here? |
@skateman sorry; conference-brain. My concern was in here: https://github.com/rails/rails/pull/34716/files#diff-e7a49345fe344d173cbcd874c21a1a61R203 If However, looking back over this now, I'm worried it moves us much closer to a scenario where a malicious site can bypass the origin check entirely. Are we sure a nefarious proxy can't use this to make a victim browser successfully connect to a target ACa server? (That's basically the vector the origin check is there for, right?) |
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. |
Ran into this problem recently so resurrecting this thread. I think if we don't want to trust X-Forwarded-For there are bigger issues - My idea for a fix that I'm currently testing in our deployment with a monkeypatch is this: request = Rack::Request.new(env)
proto = request.ssl? ? "https" : "http"
if server.config.allow_same_origin_as_host && env["HTTP_ORIGIN"] == "#{proto}://#{request.host_with_port}"
true
# ... |
When using
allow_same_origin_as_host
with a reverse proxy theHOST
header is set to the proxy host which will cause the CSRF protection to forbid the request. Each time a request hits a reverse proxy, itupdated the HOST header and also prepends the host from the previous request to the
X-FORWARDED-FOR
header. When the request finally hits the server where ActionCable is running, the first host in the header will be the right one for us.I am proposing to change my original idea introduced in 268c340 to test against the first element of this header when it is set.