This post originated from an RSS feed registered with Python Buzz
by Ian Bicking.
Original Post: Security Models
Feed Title: Ian Bicking
Feed URL: http://www.ianbicking.org/feeds/atom.xml
Feed Description: Thoughts on Python and Programming.
I've been thinking about security models lately, as I'm presented with
creating one for a CMS I've been working on. But I don't feel like I
have a lot of good models to work off of.
The traditional Unix model has some positive points. Quick review:
each object has an owner and a group owner, and you can set
permissions for the owner, any member of the group, and everyone
else. The positive is that this system is easy to implement, easy to
understand, and easy to audit. It's very concrete, and it can be
presented quite succinctly in the output of ls -l.
But there's lots of negatives too. It's obviously not very flexible
-- just one owner, and one group owner. But there's also lots of
other confusions. How does the container (directory) relate to the
object (file)? What permissions do new objects get? There's several
things that interact here -- sticky bits, imask, and probably other
things I'm not even aware of. And in the end this still isn't
expressive enough -- ownership and permission is frequently messed up
(at least where users are involved).
An alternative is Access Control Lists (ACLs). These are pretty much
like traditional Unix permissions, only where's there's just one owner
and group there, you can have lists of them with ACLs. This can get
you out of some binds, but does it really help things that much?
Where Unix permissions can be unnecessarily eclectic, at least they
are easy to review -- ACLs are dense and prone to organic growth.
They are difficult to audit, and it is difficult to really have a
sense of the overall permissions for a system -- you only can know the
permissions for one file at a time.
And just like Unix permissions, it's hard to understand future
objects. Where do new files' permissions come from? The container,
the creating user, the file type, the creating software? And how do
you change that policy?
Neither system is very useful when translated to a more general system
like a CMS. Filesystems are easy, at least, because the set of
operations is so small -- you create, read, and write. The set of
permissions for a folder in a Zope instance has 88 different actions,
times how ever many roles you have, with the option of inheriting from
the container (so you have to look through a bunch of different
screens to figure out what the actual permissions for one location
is). This is not a setup that encourages good security -- it's
essentially an ACL, except where only groups are assigned permissions,
never individual users. (But at least the permissions of new objects
are easy to ascertain, as they are all dynamically inherited)
I think object-oriented permission schemes are much better. By
object-oriented I mean: expressed with code, not data. You don't have
data about objects, you ask objects about themselves; you don't do
things with objects, you ask objects to do things for themselves.
It's all much more ad hoc as a result, and likely requires real
programming to make changes to the system. But I would say that a few
lines of code are superior to a big table of values -- the
heterogeneous structures we create on demand are more expressive and
less prone to bugs than are larger, more general homogeneous data
structures. I can express the typical Zope security table with only a
couple lines of (pseudo-) code:
class ...
def permitted(self, user, action):
return self.container.permitted(user, action)
I.e., acquire all permissions from your container. When using these
kind of dynamic permissions, it's possible to be so much more
expressive, because you have access to the eclectic data that is
relevant to each object. For instance, you might allow a user to
modify, in a limited manner, documents that point to a document which
they have control over. Or you can introduce explicit delegation of
permissions in certain contexts. For any domain there's a large
number of potential, specific rules that might govern permissions.
Unfortunately, having chosen this ad hoc route, you've given yourself
so many degrees of freedom that it's hard to figure out which way to
go. Sure, that permitted function seemed easy enough. But a
real system needs to know more than that -- for an action, what are
the users that can perform it? For a user and action, what are the
objects for which they are permitted? And (for symmetry) for a user
and object, what actions are permitted? How do you present an
interface for changing particulars of the permissions? As you change
those functions, how do you update objects, how do you delegate
responsibility between objects? These are all typical programming
questions, and their solutions are even that particular to security,
but they are also questions that are often answered incorrectly and
refactoring permissions can seem as daunting as writing them in the
first place. It seems like there's not enough precedent to serve as a
guide, there's not enough examples of transparent yet powerful and
flexible systems.
While I don't know the underlying code, I suspect Zope is as general
as what I've described. But presented with this freedom, most
programmers of subsystems for Zope have simply used the tabular system
that seems so straight forward, if not elegant. It's easier to build
an ACL instead of finding something domain-specific.
Are there systems out there worth inspection and immitation? Please
tell, be they databases, filesystems, client/server applications, web
applications, or anything else.