diff --git a/gunicorn/config.py b/gunicorn/config.py index 144acaecc..4227cfa50 100644 --- a/gunicorn/config.py +++ b/gunicorn/config.py @@ -1261,17 +1261,18 @@ class ForwardedAllowIPS(Setting): cli = ["--forwarded-allow-ips"] meta = "STRING" validator = validate_string_to_list - default = os.environ.get("FORWARDED_ALLOW_IPS", "127.0.0.1") + default = os.environ.get("FORWARDED_ALLOW_IPS", "127.0.0.1,::1") desc = """\ Front-end's IPs from which allowed to handle set secure headers. (comma separate). - Set to ``*`` to disable checking of Front-end IPs (useful for setups + Set to ``*`` to disable checking of Front-end IPs. This is useful for setups where you don't know in advance the IP address of Front-end, but - you still trust the environment). + instead have ensured via other means that none other than your + authorized Front-ends can access gunicorn. By default, the value of the ``FORWARDED_ALLOW_IPS`` environment - variable. If it is not defined, the default is ``"127.0.0.1"``. + variable. If it is not defined, the default is ``"127.0.0.1,::1"``. .. note:: @@ -2358,6 +2359,9 @@ class HeaderMap(Setting): The value ``dangerous`` matches the previous, not advisabble, behaviour of mapping different header field names into the same environ name. + The (at this time, not configurable) header `SCRIPT_NAME` is permitted + without consulting this setting, if it is received from an allowed forwarder. + Use with care and only if necessary and after considering if your problem could instead be solved by specifically renaming or rewriting only the intended headers on a proxy in front of Gunicorn. diff --git a/gunicorn/http/message.py b/gunicorn/http/message.py index 88ffa5a25..75cd3ecb0 100644 --- a/gunicorn/http/message.py +++ b/gunicorn/http/message.py @@ -77,6 +77,7 @@ def parse_headers(self, data, from_trailer=False): # handle scheme headers scheme_header = False secure_scheme_headers = {} + allowed_forwarder_headers = [] if from_trailer: # nonsense. either a request is https from the beginning # .. or we are just behind a proxy who does not remove conflicting trailers @@ -85,6 +86,7 @@ def parse_headers(self, data, from_trailer=False): not isinstance(self.peer_addr, tuple) or self.peer_addr[0] in cfg.forwarded_allow_ips): secure_scheme_headers = cfg.secure_scheme_headers + allowed_forwarder_headers = ["SCRIPT_NAME"] # Parse headers into key/value pairs paying attention # to continuation lines. @@ -140,7 +142,10 @@ def parse_headers(self, data, from_trailer=False): # HTTP_X_FORWARDED_FOR = 2001:db8::ha:cc:ed,127.0.0.1,::1 # Only modify after fixing *ALL* header transformations; network to wsgi env if "_" in name: - if self.cfg.header_map == "dangerous": + if name in allowed_forwarder_headers: + # This forwarder may override our environment + pass + elif self.cfg.header_map == "dangerous": # as if we did not know we cannot safely map this pass elif self.cfg.header_map == "drop":