Server side trojan issue
Zope provides several object types that may be thought of as "executable" content. DTMLDocuments, DTMLMethods and SQLMethods are examples of executable content.
Under the current Zope security model, a DTMLMethod author can create a method containing code that attempts to perform actions above the author's level of privilege. If the author attempts to run this method, he will get an error because he is not sufficiently privileged to perform the actions. However, if the author can arrange for a more privileged user to view his content, the code will run, possibly performing actions without the higher-privileged user even knowing about it. This hole results from the fact that DTMLMethods execute with the privileges of the user executing the method.
Who is affected
Any site that allows untrusted users to create or edit "executable" content (DTML Documents, DTML Methods or SQL Methods currently) could be affected by this problem.
Zope 2.2 will contain changes to prevent this issue. In the meantime, managers of potentially affected sites should take some operational precautions to reduce their risk.
- Do not view untrusted content while logged in with privileges that could be abused and always end your session with those privileges as soon as your work is done.
- Create temporary users with "just enough privilege" to do a particular task and perform as much work as possible with these restricted privilege users.
- Keep an eye on your site for suspicious activity - looking at the "undo" tab on the top-level folder of your site is a good way to get an idea of who has been doing what.
- Keep good backups (which you should of course do anyway), and if possible avoid packing your site - that will give you most options for undoing site changes if you need to.
In Zope 2.2.0, the security model will be changed to prevent this issue. When executing, an executable (an object that executes logic supplied through the Web) will provide access to a protected resource only if the resource is accessible to both the user running the executable and to the owner of the executable.
That's right, we are finally going to define honest to God owners. For starters, when an executable is created by a authenticated user other than the superuser, the authenticated user will become the owner of the executable. An executable is created when someone adds one or when one is copied or imported.
Note that the superuser cannot be an owner. Furthermore, the superuser is (as of 2.2) not allowed to create, copy, or move objects. In effect, we are diminishing the role and capabilities of superuser. The superuser should only be used for creating new users, including users with management responsibilities and for fixing up permissions that might be set incorrectly or maliciously by ordinary users.
The executable will not store a direct reference to the owner. Rather, a tuple consisting of the physical path to the owner's database and the id of the owner within the database will be stored. When an actual owner is needed at run-time, the user database path and the owner id will be used to look up the owner.
What is the relationship between the owner and owner roles?
They are mostly independent. Whenever an owner is changed, the new owner will get the owner role on the object. The exception is the unlikely case in which the new owner is the special user nobody. The nobody user never gets the owner role.
Only one user can be the owner. Many users can have the owner role. Owner roles can be changed without changing the owner.
There is a tradeoff between the possible confusion of the two terms, "owner" and "owner role", and the use of a non-standard term (e.g. "responsibility") for something that most people think of under the word ownership. After some angst, it was decided that the terms "owner" and "owner role" are sufficiently distinct. Clearly they are similar and related. When an object is created, the creating user is the owner and is the only person who has the owner role. They are allowed to delegate ownership duties by giving others the owner role, but this is fairly rare in practice.
What else does ownership mean?
All Zope objects may be owned. Currently, ownership is most meaningful for executable objects, since ownership constrains the access that they have. The ownership of collection objects will be acquired by sub-objects, where possible.
What happens if the owner goes away?
What if someone deletes the owner from the user database, or
deletes the user database? If the owner can't be found, then we'll use
the special user
nobody, which is extremely unprivileged.
Does this also apply to the case where an object is referenced from a side of the tree where the owner doesn't exist?
- No. The owner is not acquired. It is stored as the absolute path to the user database and a unique id. So, unless the owner has moved or gone away, we can still find the owner. Of course, the owner may have no privilege to access protected resources in the side tree.
Say I'm in
/a/b, and I do
which is owned by someone in
/a/c. But I only
/a/b. What happens?
- It depends on what you try to do.
If std_header is unprotected and only accesses unprotected resources, then there is no problem. Otherwise, the access will be unauthorized.
Can the owner be changed?
Yes. Those users having the "Take ownership" permission will be able to take ownership of objects using a new "Ownership" tab in the Zope management interface. Note that ownership may not be given away, only taken explicitly.
How does the superuser fit in?
The superuser is never an owner. The superuser is prohibited from adding (or copying, moving, or importing) objects.
- What about objects that are created by the "system"?
For instance, a ZClass that is installed by a product automatically. Who owns this?
- No one. It is unowned, for two reasons:
- Object in the control panel (e.g. ZClasses) are never owned,
- There is now a special user, system, that performs any operations done during startup. The system user is allowed to create objects and the objects created by the system user are either unowned or acquire their ownership from the place they are added.
Another question: what about revisions? Let's say paul is a manager and jim is a manager. One day paul creates
foo. Then jim comes along and edits it. Who is the owner of foo? Who is the owner of the previous revision of foo?
- paul. Ownership is unaffected by editing. A user must explicitly take ownership of an existing object to become its owner.
- hang on. Doesn't this introduce the original problem again? What if jim was only an owner? He introduces a trojan by editing the object(which he doesn't have rights to execute, but Paul (the owner, even after edit) does), then the next time someone with sufficient rights to execute the trojan views the document, the trojan gets executed as before (because Paul, the owner, has rights to execute the code as he's a manager)?
- I'm not sure, but you can only be an owner if your an authenticated user. As far as I understood,
nobodyisn't an authenticated user. Thus the trojan will not be executed, because it hasn't got an owner? Am I right here? Of course, you've to trust your authenticated users. Or am I wrong again here?
- I may be wrong but I thought the problem was authenticated users, who didn't have sufficient right, adding trojans which got successfully executed when someone who did have sufficient rights viewed them? If so, then I think the situation I describe above is correct.
Answers to ZifNab?'s questions:
- The trojan will have an owner, Jim, because ownership is unaffected by editing.
- I wouldn't trust most authenticated users ;-)
- this is a standard issue with set-uid programs in Unix. The standard solution is: don't give permission to edit executable objects to users who you wouldn't trust executing them. There's really nothing else you can do...
Handling of unowned executables
If an unowned executable is called directly or indirectly from another executable, then the executable can access resources as long as the person running the executable can. In other words, the behavior is the same as for Zope 2.1.6 and earlier.
If an unowned executable is called from an owned executable, then the unowned executable operates as though it had the owned executable's owner.
- Couldn't someone get the same TrojanHorse? functionality just by contriving for a dtml method to be unowned?
- It isn't possible to contrive to make an object
outside of the control panel unowned. It would be necessary to
have extreme (
Manager:) privileges to make unowned objects in the control panel. Someone with that level of priviledge would not need the Trojan Horse.
Objects in the Control Panel
All objects in the control panel are unowned, including ZClasses and their methods.
Bonus hole: Proxy roles
In exploring an alternate solution for the Trojan horse, another hole was discovered. A user can set proxy roles if they have permission to set proxy roles, and if they have the roles they are trying to add at the place that they are set. When a method with proxy roles is run, it can access objects that require the roles anywhere, including places where the user who set the proxy roles doesn't have the roles!
Proxy Roles NG
The meaning of Proxy roles is changing.
An executable never has more roles that it's owner.
If an executable has any proxy roles set, then the executable executes with those roles as long as the owner has the roles, regardless of whether the authenticated user has the roles. So proxy roles can be used to allow an executable to do things that the authenticated user can't.
In addition, if proxy roles are set, then an executable can't access
objects requiring roles that are not listed in the proxy roles, even
if the owner or authenticated user have the required roles. In this
way, proxy roles can limit, as well as expand access. For example,
on zope.org. one would want to arrange for Wiki pages to have the
Member proxy roles.
- What is the scope of proxy roles?
Currently in 2.1.6 proxy roles only have an effect for DTML objects that are not called from other DTML objects. This is somewhat broken. For 2.2, if an object has proxy roles then those proxy roles will have an effect on the object whether or not it is called as a sub- document. The effect of the proxy roles of the current document will not apply to sub-documents however.
A better security API
As work was being done to fix this issue, it became clear that the implementation of Zope's security policy enforcement was too widely scattered across the codebase, making it difficult to easily make basic changes to the policy. A side benefit of working on this issue is the development of a much better security api that provides a common abstraction and interface for checking and enforcing Zope security. An explanation of the new security policy infrastructure is located in the Interfaces Wiki on Zope.org::
An alpha of Zope 2.2 will be released this week. The 2.2 release will be going through an alpha and beta period to be sure that these changes are tested in a broad variety of environments before final release, and to uncover any hidden migration issues that need to be captured for the final release. A discussion of the possible migration issues for upgrading from 2.1.x will accompany the alpha release and be revised during the alpha and beta period.