Repository: pallets/werkzeug

Issue:
Enable x_host and x_proto by default through deprecated proxyfix?
When #1314 refactored ProxyFix, it aliased num_proxies to x_for only (as that was the only one which previously supported multiple proxies).

However in doing so it disabled forwarding of host and scheme, [which were forwarded by default up to 0.14](https://github.com/pallets/werkzeug/blob/f1d15a2c7f35dcde0e52787c9fdf9ea6f6405308/werkzeug/contrib/fixers.py#L146-L151), which breaks systems relying on this.

I'd like to set x_host=1 and x_proto=1 in 0.15 IFF the user goes through the deprecated wrapper (`werkzeug.contrib.fixers.ProxyFix`) in order to restore the old behaviour, and maybe add a small warning about this behavioural change to the deprecation message (or possibly in one of the `versionchanged` blocks of the new version). Would that be acceptable / interesting or a waste of time?


Discussion:
Yeah, that sounds good.

I'm fine with adding `x_proto=1` for both, not just for the deprecated wrapper, since we think it's fairly low impact on security.

`x_host` I'm less confident about going forward, as I'm not sure what the impact is if the client can control `Host` through `X-Forwarded-Host` when Nginx isn't configured to set it. Odoo probably has a better understanding of HTTP security than I do, so if you have a good argument for leaving it enabled, I'm interested in hearing it.

Resolving patch:
diff --git a/src/werkzeug/middleware/proxy_fix.py b/src/werkzeug/middleware/proxy_fix.py
--- a/src/werkzeug/middleware/proxy_fix.py
+++ b/src/werkzeug/middleware/proxy_fix.py
@@ -77,7 +77,7 @@ class ProxyFix(object):
     """
 
     def __init__(
-        self, app, num_proxies=None, x_for=1, x_proto=0, x_host=0, x_port=0, x_prefix=0
+        self, app, num_proxies=None, x_for=1, x_proto=1, x_host=0, x_port=0, x_prefix=0
     ):
         self.app = app
         self.x_for = x_for
@@ -112,11 +112,15 @@ def num_proxies(self, value):
         if value is not None:
             warnings.warn(
                 "'num_proxies' is deprecated as of version 0.15 and"
-                " will be removed in version 1.0. Use 'x_for' instead.",
+                " will be removed in version 1.0. Use"
+                " 'x_for={value}, x_proto={value}, x_host={value}'"
+                " instead.".format(value=value),
                 DeprecationWarning,
                 stacklevel=2,
             )
             self.x_for = value
+            self.x_proto = value
+            self.x_host = value
 
     def get_remote_addr(self, forwarded_for):
         """Get the real ``remote_addr`` by looking backwards ``x_for``


Test patch:
diff --git a/tests/middleware/test_proxy_fix.py b/tests/middleware/test_proxy_fix.py
--- a/tests/middleware/test_proxy_fix.py
+++ b/tests/middleware/test_proxy_fix.py
@@ -18,8 +18,9 @@
                 "REMOTE_ADDR": "192.168.0.2",
                 "HTTP_HOST": "spam",
                 "HTTP_X_FORWARDED_FOR": "192.168.0.1",
+                "HTTP_X_FORWARDED_PROTO": "https",
             },
-            "http://spam/",
+            "https://spam/",
             id="for",
         ),
         pytest.param(
@@ -178,6 +179,8 @@ def app(request):
 def test_proxy_fix_deprecations():
     app = pytest.deprecated_call(ProxyFix, None, 2)
     assert app.x_for == 2
+    assert app.x_proto == 2
+    assert app.x_host == 2
 
     with pytest.deprecated_call():
         assert app.num_proxies == 2