-
-
Notifications
You must be signed in to change notification settings - Fork 82
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
Respect X-Forwarded-Proto header #87
Conversation
cc0b873
to
ad0c43e
Compare
All three of these commits actually have the same effect (I was thrown off by #88), so take your pick which one you'd like and I'll rebase things. |
@@ -105,6 +105,7 @@ def unwrap_request(request, env) | |||
# https://tools.ietf.org/html/rfc7239#section-5.4 | |||
# https://github.com/rack/rack/issues/1310 | |||
env[HTTP_X_FORWARDED_PROTO] ||= request.scheme | |||
env[RACK_URL_SCHEME] = env[HTTP_X_FORWARDED_PROTO] |
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.
Did we set RACK_URL_SCHEME
anywhere else or did I just completely miss it?
Also, is this checked by rack linter?
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.
RACK_URL_SCHEME
defaults to request.scheme
, however that's not accurate in cases where we're listening on HTTP but have SSL terminated upstream.
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.
If the user sent the X-Forwarded-Proto: https
could that break the application that's running on http
? Just wondering if there are security implications to this.
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.
For context, here's how puma sets RACK_URL_SCHEME
:
env[RACK_URL_SCHEME] = default_server_port(env) == PORT_443 ? HTTPS : HTTP
Here's default_server_port
:
def default_server_port(env)
if ['on', HTTPS].include?(env[HTTPS_KEY]) || env[HTTP_X_FORWARDED_PROTO].to_s[0...5] == HTTPS || env[HTTP_X_FORWARDED_SCHEME] == HTTPS || env[HTTP_X_FORWARDED_SSL] == "on"
PORT_443
else
PORT_80
end
end
In theory if the application was exposed directly, you could bypass middleware to force ssl by sending X-Forwarded-Proto: https
. Whether or not that has security implications I don't know, since it could only affect the current user's session.
I'm not certain on this, but I would think it's up to nginx, haproxy, or whatever is used in front of the application to set or reject these headers. Here's how Heroku handles 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.
@ioquatix the purpose of the scheme check is to protect the user from sending information over unencrypted connections. If the user provides the X-Forwarded-Proto: https
it will only impact them. I don't think this is a security concern.
Thanks @bryanp - The security issues are less of a concern, but I do want to hear more about it if anyone has any other concerns. Using the user facing headers... should probably be something explicit in the app... as it stands, the protocol reported by falcon is the last hop... but in this case we want the first hop... |
Typically this header will get explicitly set by the server doing SSL termination. I've tested this on Heroku and even if I send |
Sorry, I have not come back to this and it's been sitting for a while. There are a few options:
There is one other issue. The HTTP/2 pseudo header I don't really have a strong feeling on this right now, except that what we are doing is already the simplest and most straight forward approach. Should What's stopping applications from parsing out the I'm all for making those headers easier to work with, and I don't even mind if we should use a more elaborate method for setting the default Thoughts? |
Bearing in mind, that if the client connection is HTTP, but the internal connection is HTTPS, that's also confusing. What is |
77ce8ce
to
98a0ae6
Compare
71effb6
to
827cf81
Compare
8a55246
to
f785c4d
Compare
I discussed this with @jeremyevans and we are going to clarify The current behaviour of Falcon is the only safe default. Overriding In principle, you can use However, in Falcon, if you use |
This is an attempt to resolve #86