summaryrefslogtreecommitdiff
path: root/tests/servers
diff options
context:
space:
mode:
authorCarl Meyer <carl@oddbird.net>2014-09-10 11:06:19 -0600
committerTim Graham <timograham@gmail.com>2015-01-13 13:03:05 -0500
commit316b8d49746933d1845d600314b002d9b64d3e3d (patch)
treed272f2d0a1a0c70c4d1cb5a9fd525629357061dd /tests/servers
parent958aeda4b5efcde30438979d93fc585a2f12ce02 (diff)
Stripped headers containing underscores to prevent spoofing in WSGI environ.
This is a security fix. Disclosure following shortly. Thanks to Jedediah Smith for the report.
Diffstat (limited to 'tests/servers')
-rw-r--r--tests/servers/test_basehttp.py55
1 files changed, 55 insertions, 0 deletions
diff --git a/tests/servers/test_basehttp.py b/tests/servers/test_basehttp.py
index 41e9258bf5..7352adf287 100644
--- a/tests/servers/test_basehttp.py
+++ b/tests/servers/test_basehttp.py
@@ -6,6 +6,11 @@ from django.test.utils import captured_stderr
from django.utils.six import BytesIO
+class Stub(object):
+ def __init__(self, **kwargs):
+ self.__dict__.update(kwargs)
+
+
class WSGIRequestHandlerTestCase(TestCase):
def test_https(self):
request = WSGIRequest(RequestFactory().get('/').environ)
@@ -20,3 +25,53 @@ class WSGIRequestHandlerTestCase(TestCase):
"but it only supports HTTP.",
stderr.getvalue()
)
+
+ def test_strips_underscore_headers(self):
+ """WSGIRequestHandler ignores headers containing underscores.
+
+ This follows the lead of nginx and Apache 2.4, and is to avoid
+ ambiguity between dashes and underscores in mapping to WSGI environ,
+ which can have security implications.
+ """
+ def test_app(environ, start_response):
+ """A WSGI app that just reflects its HTTP environ."""
+ start_response('200 OK', [])
+ http_environ_items = sorted(
+ '%s:%s' % (k, v) for k, v in environ.items()
+ if k.startswith('HTTP_')
+ )
+ yield (','.join(http_environ_items)).encode('utf-8')
+
+ rfile = BytesIO()
+ rfile.write(b"GET / HTTP/1.0\r\n")
+ rfile.write(b"Some-Header: good\r\n")
+ rfile.write(b"Some_Header: bad\r\n")
+ rfile.write(b"Other_Header: bad\r\n")
+ rfile.seek(0)
+
+ # WSGIRequestHandler closes the output file; we need to make this a
+ # no-op so we can still read its contents.
+ class UnclosableBytesIO(BytesIO):
+ def close(self):
+ pass
+
+ wfile = UnclosableBytesIO()
+
+ def makefile(mode, *a, **kw):
+ if mode == 'rb':
+ return rfile
+ elif mode == 'wb':
+ return wfile
+
+ request = Stub(makefile=makefile)
+ server = Stub(base_environ={}, get_app=lambda: test_app)
+
+ # We don't need to check stderr, but we don't want it in test output
+ with captured_stderr():
+ # instantiating a handler runs the request as side effect
+ WSGIRequestHandler(request, '192.168.0.2', server)
+
+ wfile.seek(0)
+ body = list(wfile.readlines())[-1]
+
+ self.assertEqual(body, b'HTTP_SOME_HEADER:good')