Commit 8ed2f2b6 authored by Jason Madden's avatar Jason Madden

Strip incoming headers that contain an underscore. Fixes #819.

parent ff5ca13b
...@@ -46,6 +46,8 @@ Security ...@@ -46,6 +46,8 @@ Security
``start_response`` do not contain a carriage return or newline in ``start_response`` do not contain a carriage return or newline in
order to prevent HTTP response splitting (header injection), raising order to prevent HTTP response splitting (header injection), raising
a :exc:`ValueError` if they do. See :issue:`775`. a :exc:`ValueError` if they do. See :issue:`775`.
- Incoming headers containing an underscore are no longer placed in
the WSGI environ. See :issue:`819`.
- Errors logged by :class:`~gevent.pywsgi.WSGIHandler` no - Errors logged by :class:`~gevent.pywsgi.WSGIHandler` no
longer print the entire WSGI environment by default. This avoids longer print the entire WSGI environment by default. This avoids
possible information disclosure vulnerabilities. Applications can possible information disclosure vulnerabilities. Applications can
......
...@@ -1010,18 +1010,23 @@ class WSGIHandler(object): ...@@ -1010,18 +1010,23 @@ class WSGIHandler(object):
def _headers(self): def _headers(self):
key = None key = None
value = None value = None
IGNORED_KEYS = (None, 'CONTENT_TYPE', 'CONTENT_LENGTH')
for header in self.headers.headers: for header in self.headers.headers:
if key is not None and header[:1] in " \t": if key is not None and header[:1] in " \t":
value += header value += header
continue continue
if key not in (None, 'CONTENT_TYPE', 'CONTENT_LENGTH'): if key not in IGNORED_KEYS:
yield 'HTTP_' + key, value.strip() yield 'HTTP_' + key, value.strip()
key, value = header.split(':', 1) key, value = header.split(':', 1)
if '_' in key:
# strip incoming bad veaders
key = None
else:
key = key.replace('-', '_').upper() key = key.replace('-', '_').upper()
if key not in (None, 'CONTENT_TYPE', 'CONTENT_LENGTH'): if key not in IGNORED_KEYS:
yield 'HTTP_' + key, value.strip() yield 'HTTP_' + key, value.strip()
def get_environ(self): def get_environ(self):
......
...@@ -36,7 +36,7 @@ from gevent.hub import _get_hub ...@@ -36,7 +36,7 @@ from gevent.hub import _get_hub
from functools import wraps from functools import wraps
import contextlib import contextlib
import gc import gc
import six import _six as six
PYPY = hasattr(sys, 'pypy_version_info') PYPY = hasattr(sys, 'pypy_version_info')
......
"""Check __all__, __implements__, __extensions__, __imports__ of the modules""" """Check __all__, __implements__, __extensions__, __imports__ of the modules"""
from __future__ import print_function from __future__ import print_function
import six import _six as six
import sys import sys
import unittest import unittest
import types import types
......
...@@ -2,7 +2,7 @@ import greentest ...@@ -2,7 +2,7 @@ import greentest
import gevent import gevent
from gevent import socket from gevent import socket
from gevent import backdoor from gevent import backdoor
from six import xrange from _six import xrange
def read_until(conn, postfix): def read_until(conn, postfix):
......
import greentest import greentest
import gevent import gevent
from gevent.event import Event, AsyncResult from gevent.event import Event, AsyncResult
from six import xrange from _six import xrange
DELAY = 0.01 DELAY = 0.01
......
import gevent import gevent
import sys import sys
import greentest import greentest
import six import _six as six
if not six.PY3: if not six.PY3:
sys.exc_clear() sys.exc_clear()
......
from greentest import walk_modules, BaseTestCase, main, NON_APPLICABLE_SUFFIXES from greentest import walk_modules, BaseTestCase, main, NON_APPLICABLE_SUFFIXES
import six import _six as six
class TestExec(BaseTestCase): class TestExec(BaseTestCase):
......
import gevent import gevent
import greentest import greentest
from six import xrange from _six import xrange
class appender(object): class appender(object):
......
import sys import sys
import six import _six as six
from os import pipe from os import pipe
from gevent import os from gevent import os
from greentest import TestCase, main from greentest import TestCase, main
......
...@@ -6,7 +6,7 @@ from gevent.queue import Queue ...@@ -6,7 +6,7 @@ from gevent.queue import Queue
import greentest import greentest
import random import random
from greentest import ExpectedException from greentest import ExpectedException
import six import _six as six
import unittest import unittest
......
...@@ -1363,6 +1363,21 @@ class TestInvalidEnviron(TestCase): ...@@ -1363,6 +1363,21 @@ class TestInvalidEnviron(TestCase):
read_http(fd) read_http(fd)
class TestInvalidHeadersDropped(TestCase):
validator = None
# check that invalid headers with a _ are dropped
def application(self, environ, start_response):
self.assertNotIn('HTTP_X_AUTH_USER', environ)
start_response('200 OK', [])
return []
def test(self):
fd = self.makefile()
fd.write('GET / HTTP/1.0\r\nx-auth_user: bob\r\n\r\n')
read_http(fd)
class Handler(pywsgi.WSGIHandler): class Handler(pywsgi.WSGIHandler):
def read_requestline(self): def read_requestline(self):
......
import six import _six as six
import sys import sys
import os import os
import errno import errno
......
...@@ -7,7 +7,7 @@ import traceback ...@@ -7,7 +7,7 @@ import traceback
import time import time
import greentest import greentest
from functools import wraps from functools import wraps
import six import _six as six
# we use threading on purpose so that we can test both regular and gevent sockets with the same code # we use threading on purpose so that we can test both regular and gevent sockets with the same code
from threading import Thread as _Thread from threading import Thread as _Thread
......
#!/usr/bin/python #!/usr/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import six import _six as six
import re import re
import greentest import greentest
import socket import socket
...@@ -8,7 +8,7 @@ from time import time ...@@ -8,7 +8,7 @@ from time import time
import gevent import gevent
import gevent.socket as gevent_socket import gevent.socket as gevent_socket
from util import log from util import log
from six import xrange from _six import xrange
resolver = gevent.get_hub().resolver resolver = gevent.get_hub().resolver
......
import sys import sys
from six import xrange from _six import xrange
if 'runtestcase' in sys.argv[1:]: if 'runtestcase' in sys.argv[1:]:
......
...@@ -7,7 +7,7 @@ import gevent.threadpool ...@@ -7,7 +7,7 @@ import gevent.threadpool
from gevent.threadpool import ThreadPool from gevent.threadpool import ThreadPool
import gevent import gevent
from greentest import ExpectedException from greentest import ExpectedException
import six import _six as six
import gc import gc
......
...@@ -2,7 +2,7 @@ from contextlib import contextmanager ...@@ -2,7 +2,7 @@ from contextlib import contextmanager
import gevent import gevent
from gevent.event import Event from gevent.event import Event
from time import time from time import time
from six import xrange from _six import xrange
SMALL = 0.1 SMALL = 0.1
......
...@@ -9,7 +9,7 @@ try: ...@@ -9,7 +9,7 @@ try:
from test import support as test_support from test import support as test_support
except ImportError: except ImportError:
from test import test_support from test import test_support
from six import xrange from _six import xrange
QUEUE_SIZE = 5 QUEUE_SIZE = 5
......
# testing gevent's Event, Lock, RLock, Semaphore, BoundedSemaphore with standard test_threading # testing gevent's Event, Lock, RLock, Semaphore, BoundedSemaphore with standard test_threading
from __future__ import print_function from __future__ import print_function
from six import xrange from _six import xrange
setup_ = '''from gevent import monkey; monkey.patch_all() setup_ = '''from gevent import monkey; monkey.patch_all()
from gevent.event import Event from gevent.event import Event
......
#!/usr/bin/env python #!/usr/bin/env python
from __future__ import print_function from __future__ import print_function
import six import _six as six
import sys import sys
import os import os
import glob import glob
......
import sys import sys
import os import os
import six import _six as six
import traceback import traceback
import unittest import unittest
import threading import threading
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment