[Zope] REMOTE_USER Security Issue

Cliff Ford Cliff.Ford at ed.ac.uk
Wed May 17 17:01:01 EDT 2006


This is just to report that this issue is resolved (for me). Tres Seaver 
kindly provided a patch for HTTPRequest.py that makes the environ 
dictionary immutable (appended below for those in a similar position). 
This may have adverse consequences for applications that rely on 
existing behaviour and Tres has recommended that it would be better to 
harden the User Folder code. In our case we might also be able to 
encrypt the remote Username. Once again, thanks to Tres and other list 
members, who are a wonderful resource.

Cliff

Cliff Ford wrote:
> My people want to adopt a single sign-on system for web applications 
> that is based on the REMOTE_USER environment variable. I have tried out 
> RemoteUserFolder and also adapted exUserFolder to work similarly.
> 
> My problem is that I figured out how a user who has permission to create 
> python scripts (might work with dtml and page templates too) could 
> access otherwise forbidden content by making calls that pretend to come 
> from another user. Has any one else come across this problem and devised 
> a solution, either in software or organisation?
> 
> Problem verified with Zope 2.9.2 and latest RemoteUserFolder.
> 
> Cliff
> _______________________________________________
> Zope maillist  -  Zope at zope.org
> http://mail.zope.org/mailman/listinfo/zope
> **   No cross posts or HTML encoding!  **
> (Related lists - http://mail.zope.org/mailman/listinfo/zope-announce
> http://mail.zope.org/mailman/listinfo/zope-dev )

The Patch:

Index: lib/python/ZPublisher/HTTPRequest.py
===================================================================
--- lib/python/ZPublisher/HTTPRequest.py	(revision 68139)
+++ lib/python/ZPublisher/HTTPRequest.py	(working copy)
@@ -63,6 +63,16 @@
  class NestedLoopExit( Exception ):
      pass

+class ReadOnlyDict(dict):
+    def __setitem__(self, key, value):
+        raise TypeError, 'Immutable'
+    def __delitem__(self, key):
+        raise TypeError, 'Immutable'
+    def update(self, other):
+        raise TypeError, 'Immutable'
+    def clear(self):
+        raise TypeError, 'Immutable'
+
  class HTTPRequest(BaseRequest):
      """\
      Model HTTP request data.
@@ -252,7 +262,7 @@
              del environ['HTTP_AUTHORIZATION']

          self.stdin=stdin
-        self.environ=environ
+        self.environ=ReadOnlyDict(environ)
          have_env=environ.has_key
          get_env=environ.get
          self.response=response
Index: lib/python/ZPublisher/tests/testHTTPRequest.py
===================================================================
--- lib/python/ZPublisher/tests/testHTTPRequest.py	(revision 68139)
+++ lib/python/ZPublisher/tests/testHTTPRequest.py	(working copy)
@@ -684,7 +684,23 @@
          req.close()
          self.assertEqual(start_count, sys.getrefcount(s))  # The test

+    def test_environ_is_immutable(self):
+        from StringIO import StringIO
+        s = StringIO(TEST_FILE_DATA)
+        env = TEST_ENVIRON.copy()
+        env['to_replace'] = 'to_replace'
+        env['to_remove'] = 'to_remove'
+        from ZPublisher.HTTPRequest import HTTPRequest
+        req = HTTPRequest(s, env, None)
+        self.assertRaises(TypeError, req.environ.__setitem__,
+                            'hacked', 'hacked')
+        self.assertRaises(TypeError, req.environ.__setitem__,
+                            'to_replace', 'replaced')
+        self.assertRaises(TypeError, req.environ.__delitem__, 'to_remove')
+        self.assertRaises(TypeError, req.environ.update, {'hacked': 
'hacked'})
+        self.assertRaises(TypeError, req.environ.clear)

+
  def test_suite():
      suite = unittest.TestSuite()
      suite.addTest(unittest.makeSuite(AuthCredentialsTestsa, 'test'))
Index: lib/python/OFS/tests/testRanges.py
===================================================================
--- lib/python/OFS/tests/testRanges.py	(revision 68139)
+++ lib/python/OFS/tests/testRanges.py	(working copy)
@@ -59,6 +59,9 @@
              r['Application'] = a
              self.root = a
              self.app = makerequest(self.root, stdout=self.responseOut)
+            # 'environ' is now immutable, so replace it to allow scribbling
+            #  in tests
+            self.app.REQUEST.environ = dict(self.app.REQUEST.environ)
              try: self.app._delObject(TESTFOLDER_NAME)
              except AttributeError: pass
              manage_addFolder(self.app, TESTFOLDER_NAME)




More information about the Zope mailing list