diff options
| author | Carl Meyer <carl@oddbird.net> | 2014-09-10 11:06:19 -0600 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2015-01-13 13:03:05 -0500 |
| commit | 316b8d49746933d1845d600314b002d9b64d3e3d (patch) | |
| tree | d272f2d0a1a0c70c4d1cb5a9fd525629357061dd /tests/servers/test_basehttp.py | |
| parent | 958aeda4b5efcde30438979d93fc585a2f12ce02 (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/test_basehttp.py')
| -rw-r--r-- | tests/servers/test_basehttp.py | 55 |
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') |
