[ZCM] [ZC] 685/14 Resolve "Security problems importing from python package."

Collector: Zope Bugs, Features, and Patches ... zope-coders-admin@zope.org
Mon, 06 Jan 2003 10:52:43 -0500


Issue #685 Update (Resolve) "Security problems importing from python package."
 Status Resolved, Zope/bug medium
To followup, visit:
  http://collector.zope.org/Zope/685

==============================================================
= Resolve - Entry #14 by chrisw on Jan 6, 2003 10:52 am

 Status: Accepted => Resolved

I'll reluctantly go with Toby and the others on this one. 
'Products' is the way to go for Zope 2.x, hopefully Zope 3 will handle this better :-(

Anyway, I've fixed it by putting some warnings in the files in the PythonScripts directory. If anyone knows of other places this should be documented, please let me know, or better yet, update them yourself :-)

Chris
________________________________________
= Comment - Entry #13 by htrd on Dec 19, 2002 9:04 am

> For me the only correct way to resolve this
> is to *not* change anything to Zope, but put it in a
> product
> After all this is Zope, the way to do components in Zope 2 is
> to add Products.

+1 for sticking to this as a principal

________________________________________
= Comment - Entry #12 by efge on Dec 19, 2002 8:45 am

I'll add my voice. For me the only correct way to resolve this
is to *not* change anything to Zope, but put stripogram in a
product and do import Products.stripogram. Because it's a product,
__init__.py will be executed by Zope and you'll be able to put
security assertions there.

After all this is Zope, the way to do components in Zope 2 is
to add Products. One shouldn't shy away from doing imports
from Products.something. That's not a problem.

________________________________________
= Comment - Entry #11 by camil7 on Dec 18, 2002 10:43 am

Very late to comment on this, but anyway:

> > 1. Give Strip-o-Gram a Product component, consisting of nothing but an
> > __init__.py with security declarations or simply "import stripogram".

> This is specifically what I'm trying to avoid. The documentation 
> doesn't say this is necessary and I don't think it should be. 

I guess the simplest way is to fix the documentation in this case ;-)
One could argue the dummy import is necessary to initialize
the module properly; this would convince at least me ;-)

 The new solution would be to put all security definitions
in a separate submodule/function, if I understand correctly?
This would mean to split the security declarations from the 
code, which I as an end user would like less than having
a dummy import somewhere.

just my 2 cents
________________________________________
= Comment - Entry #10 by chrisw on Dec 18, 2002 8:02 am

> = Comment - Entry #9 by shane on Dec 18, 2002 7:43 am
> 
> > How's this for a plan?
> > 
> > 1. Try to import xxx_zope_security from the same place as xxx is trying
> >   to be imported. Ignore if an ImportError occurs.
> 
> This is ok.

Cool :-)

> > 2. Try to import xxx.zope_security. Ignore if ImportError occurs.
> 
> This is NOT ok!  It would allow untrusted users to import any top-level
>   package.

Does that still hold true if imp.load_module is used rather than __import__?

> Whatever you do, just remember to do it on a branch first, so it can be
>   reviewed before inclusion.

Hehe, as I discovered, it gets reviewed much more quickly if you choose that branch to be Zope-2_6-branch ;-)

________________________________________
= Comment - Entry #9 by shane on Dec 18, 2002 7:43 am

> How's this for a plan?
> 
> 1. Try to import xxx_zope_security from the same place as xxx is trying
>   to be imported. Ignore if an ImportError occurs.

This is ok.

> 
> 2. Try to import xxx.zope_security. Ignore if ImportError occurs.

This is NOT ok!  It would allow untrusted users to import any top-level package.

> 3. Proceed as before.
> 
> I'll give it a go today...

Whatever you do, just remember to do it on a branch first, so it can be reviewed before inclusion.

Shane

________________________________________
= Assign - Entry #8 by chrisw on Dec 18, 2002 6:45 am

 Status: Pending => Accepted

 Supporters added: chrisw, evan, shane

> = Comment - Entry #7 by evan on Dec 17, 2002 5:37 pm
> 
> 1. Give Strip-o-Gram a Product component, consisting of nothing but an
>   __init__.py with security declarations or simply "import stripogram".

This is specifically what I'm trying to avoid. The documentation doesn't say this is necessary and I don't think it should be.

> 2. When guarded_import would otherwise refuse to import module foo, grep
>   the beginning of foo.py for a magic cookie (e.g. "#Zope: allow import"). 
>   Bleh.

Well, we have precedents for this in Script (Python)'s processing of comments, but yeah, 'bleh' feels about right.

> 3. Have guarded_import check for foo_zope.py in the same directory as
>   foo.py, and execute it prior to importing foo.

Hmmm... arg :-( 
My need wasn't as harsh as this since stripogram is a package and not a module, but this feels like the right way to go.

How's this for a plan?

1. Try to import xxx_zope_security from the same place as xxx is trying to be imported. Ignore if an ImportError occurs.

2. Try to import xxx.zope_security. Ignore if ImportError occurs.

3. Proceed as before.

I'll give it a go today...
________________________________________
= Comment - Entry #7 by evan on Dec 17, 2002 5:37 pm

Some possible solutions, just to keep the issue alive:

1. Give Strip-o-Gram a Product component, consisting of nothing but an __init__.py with security declarations or simply "import stripogram".

2. When guarded_import would otherwise refuse to import module foo, grep the beginning of foo.py for a magic cookie (e.g. "#Zope: allow import").  Bleh.

3. Have guarded_import check for foo_zope.py in the same directory as foo.py, and execute it prior to importing foo.

________________________________________
= Resubmit - Entry #6 by shane on Dec 17, 2002 3:44 pm

 Status: Resolved => Pending

Chris,

Bugs involving security always need some form of peer review.  We'll come up with a solution, but it won't be allowing anything to be imported.

________________________________________
= Comment - Entry #5 by chrisw on Dec 17, 2002 2:37 pm

Just to note that Shane has some concerns about the solution. I've left the current solution as is, pending a better solution being put forward.
________________________________________
= Resolve - Entry #4 by chrisw on Dec 17, 2002 1:11 pm

 Status: Pending => Resolved

This is now fixed on 2.6 branch and HEAD.
________________________________________
= Comment - Entry #3 by chrisw on Nov 25, 2002 11:29 am

Clemens Robbenhaar wrote:
> 
>   I did just now run into a similar problem, and may offer the following
> explanation after some debugging:
> 
>  It seems the 'allow_module', etc, gets not executed by Zope in advance,
> except if this is the __init__.py of a 'Product', or this module is
> imported by some core module or product. This is quite standard python
> behaviour; the module is not initialized before import, and Zope does
> some extra work to initialize all products on startup.
> 
>  If one tries to import the code from a python script, the security
> machinery first check, if the module has some security info, and imports
> it afterwards, if the info is found. But as the module is not imported
> anyway, it is not initialized, and has not such info and thus will not
> be allowed for import. 

This strikes me as a bug.

Zope should try and import the module before checking it's security declarations, otherwise the module has no opportunity to perform its security declarations.

Where should this importing be done?

________________________________________
= Edit - Entry #2 by chrisw on Nov 21, 2002 7:20 am

 Changes: submitter email, revised title
________________________________________
= Request - Entry #1 by chrisw on Nov 21, 2002 7:20 am

I'm trying to get stripogram working from Script(Pythons).

Now, all I should need to do is add the following to the stripogram/__init__.py:

  ModuleSecurityInfo('stripogram').declarePublic('html2text', 'html2safehtml')

This doesn't work!

In order to get the following test to pass:

  from Products.PythonScripts.PythonScript import PythonScript
  theScript = PythonScript('test')
  theScript.ZBindings_edit({})
  theScript.write("from stripogram import html2text\nreturn 
html2text('<i>hello</i>')")
  theScript._makeFunction()
  self.assertEqual(theScript(),'hello')

I also have to add:

  ModuleSecurityInfo('stripogram').declareObjectPublic()

Why?

Now, the following Script (Python) created through the ZMI:

  from stripogram import html2text

...will always result in:

  Error Type: ImportError
Error Value: import of "stripogram" is unauthorized

   File \lib\python\Products\PythonScripts\PythonScript.py, line 302, in _exec
     (Object: tester)
     (Info: ({'script': <PythonScript instance at 012CB4D8>, 'context': 
<Application instance at 012B92D8>, 'container': <Application instance at 
012B92D8>, 'traverse_subpath': []}, (), {}, None))
   File Script (Python), line 1, in tester
   File \lib\python\AccessControl\ZopeGuards.py, line 153, in guarded_import
ImportError: (see above)

Even if I add the following to stripogram/__init__.py:

     allow_module('stripogram')

Why doesn't this code behave as advertised in
Products/PythonScripts/module_access_examples.py?

==============================================================