Determine c.secure status based on X-Forwarded-Proto header.

Previously, c.secure status was determined based on the domain used.
This allows for the status to vary independently of domain for greater
flexibility.

Note: it is critical that the load balancer strips any X-Forwarded-Proto
headers that may've been sent by the client.
This commit is contained in:
Neil Williams
2013-09-03 11:32:27 -07:00
parent 552e9828ab
commit b87d87f9a5
4 changed files with 12 additions and 16 deletions

View File

@@ -333,6 +333,8 @@ frontend frontend 0.0.0.0:80
option forwardfor except 127.0.0.1
option httpclose
reqidel ^X-Forwarded-Proto:.*
default_backend dynamic
backend dynamic

View File

@@ -741,18 +741,7 @@ class MinimalController(BaseController):
c.domain_prefix = request.environ.get("reddit-domain-prefix",
g.domain_prefix)
c.secure = request.host in g.secure_domains
# wsgi.url_scheme is used in generating absolute urls, such as by webob
# for translating some of our relative-url redirects to rfc compliant
# absolute-url ones. TODO: consider using one of webob's methods of
# setting wsgi.url_scheme based on incoming request headers added by
# upstream things like stunnel/haproxy.
if c.secure:
request.environ["wsgi.url_scheme"] = "https"
# update request.fullurl since wsgi.url_scheme changed.
request.fullurl = request.host_url + request.fullpath
c.secure = request.environ["wsgi.url_scheme"] == "https"
c.request_origin = request.host_url
#check if user-agent needs a dose of rate-limiting

View File

@@ -327,16 +327,12 @@ class Globals(object):
origin_prefix = self.domain_prefix + "." if self.domain_prefix else ""
self.origin = "http://" + origin_prefix + self.domain
self.secure_domains = set([urlparse(self.payment_domain).netloc])
self.trusted_domains = set([self.domain])
self.trusted_domains.update(self.authorized_cnames)
if self.https_endpoint:
https_url = urlparse(self.https_endpoint)
self.secure_domains.add(https_url.netloc)
self.trusted_domains.add(https_url.hostname)
if getattr(self, 'oauth_domain', None):
self.secure_domains.add(self.oauth_domain)
# load the unique hashed names of files under static
static_files = os.path.join(self.paths.get('static_files'), 'static')

View File

@@ -76,6 +76,15 @@ class BaseController(WSGIController):
self.post()
def __call__(self, environ, start_response):
# we override this here to ensure that this header, and only this
# header, is trusted to reduce the number of potential
# misconfigurations between wsgi application servers (e.g. gunicorn
# which trusts three different headers out of the box for this) and
# haproxy (which won't clean out bad headers by default)
forwarded_proto = environ.get("HTTP_X_FORWARDED_PROTO", "http").lower()
assert forwarded_proto in ("http", "https")
request.environ["wsgi.url_scheme"] = forwarded_proto
true_client_ip = environ.get('HTTP_TRUE_CLIENT_IP')
ip_hash = environ.get('HTTP_TRUE_CLIENT_IP_HASH')
forwarded_for = environ.get('HTTP_X_FORWARDED_FOR', ())