diff --git a/docs/source/settings.rst b/docs/source/settings.rst index c20af3da..1bb90d55 100644 --- a/docs/source/settings.rst +++ b/docs/source/settings.rst @@ -1232,17 +1232,18 @@ the headers defined here can not be passed directly from the client. **Command line:** ``--forwarded-allow-ips STRING`` -**Default:** ``'127.0.0.1'`` +**Default:** ``'127.0.0.1,::1'`` 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:: @@ -1498,6 +1499,9 @@ The value ``refuse`` will return an error if a request contains *any* such heade 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/config.py b/gunicorn/config.py index a0366264..209d93d8 100644 --- a/gunicorn/config.py +++ b/gunicorn/config.py @@ -1263,17 +1263,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:: @@ -2365,6 +2366,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 1cb48ef3..d71ba0ab 100644 --- a/gunicorn/http/message.py +++ b/gunicorn/http/message.py @@ -78,6 +78,7 @@ class Message(object): # 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 @@ -86,6 +87,7 @@ class Message(object): 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. @@ -144,7 +146,10 @@ class Message(object): # 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":