[Grok-dev] Re: Neanderthal sprint topics

Brandon Craig Rhodes brandon at rhodesmill.org
Wed Oct 3 12:03:23 EDT 2007


Tres Seaver <tseaver at palladion.com> writes:

>  - The view renders faster, because no security checks need be done
>  *at all* in a push-model view (the class is implicitly trusted, and
>  the template only gets what the trustee gives it).

I probably misunderstand what's being discussed here, so let me
outline a quick example.

The "easy way" to do things, I suppose, is to access objects and
attributes from Genshi itself:

  <li py:for="person in context.people">
   <a href="view.url(person)">${person.name} (${person.address.street})</a>
  </li>

It seems, instead, that you are advocating that this simple and
obvious code be broken into two steps: one piece that gathers data in
the view, then a template that uses only that data for rendering:

    ...
    def update(self):
        people = [ { 'name': person.name,
                     'street_address': person.address.street,
                     'url': self.url(person) }
                   for person in self.context.people ]
        self.template_info = { 'people': people }
    ...

  <li py:for="person in people">
   <a href="person.url">${person.name} (${person.street_address})</a>
  </li>

Now, if this is the only difference you are talking about, then I'm
completely puzzled as to where you see a difference in security -
unless you are planning on having templates written by someone you do
not trust!  (Or perhaps submitted by users?)

Templates written according to the first example are much easier to
read, making it much easier to see and audit where information is
coming from than if there's a level of gratuitous indirection for the
reader to follow.  Except where obfuscation is involved, I, at least,
always find briefer and simpler code easier to check.

Now, perhaps I am wrong, and you are thinking instead about the
"if-then" logic of who-can-see-what.  For example, a student on our
campus who chooses to make their data "confidential" can not have
their name displayed except to campus personnel.  Let's imagine an app
that displays a class, and ask: where should the security check go
that protects someone's name?  One answer - a bad answer! - is "in the
view", and maybe this is the sort of thing you're objecting to:

   <li py:for="person in people">
    <a href="view.url(person)">
     <py:choose>
      <span py:when="not request.is_admin_user and person.confidential">
       CONFIDENTIAL</span>
      <span py:otherwise="">${py:person.name}</span>
     </py:choose>
    </a>
   </li>

If this is indeed what you're objecting to, then I completely agree -
these sort of checks do not belong in templates!  But, I'm going to go
a step farther, and also claim that they have no place in templates.
Doing the following is, I'll claim, just as bad:

    def update(self):

        def persondict(person):
            d = { 'street_address': person.address.street,
                  'url': self.url(person) }
            if not self.request.is_admin_user and person.confidential:
                d['name'] = 'CONFIDENTIAL'
            else:
                d['name'] = person.name
            return d

        people = [ persondict(person) for person in self.people ]
        self.template_info = { 'people': people }

Why is this just as bad?  Because this exact same logic will then have
to be repeated ten, or twenty, or thirty times, in *every single view
that could possibly need to display a person's name*!

Security checks belong neither in the template nor in the view,
because then the question "Who can see Brandon's name" can only be
answered by an exhaustive examination of every single view template
and view class in the system, followed by auditing of the templates or
classes that mention "name" anywhere in them.

Instead, the most fundamental security checks need to lie between the
view and the model.  Of course, there might be sensible restrictions
that one wants to add to views themselves ("only admins can see the
admin page", and so forth), but these are conveniences, and can never
take the place of real security itself, which always involves
protecting two sets of data:

 - Pieces of information
 - Actions or operations the user can invoke

and protecting them in such a way that they stay protected whether
they're mentioned in a view template, fetched from a view class, or
delivered when an object gets presented through an adapter. 

-- 
Brandon Craig Rhodes   brandon at rhodesmill.org   http://rhodesmill.org/brandon


More information about the Grok-dev mailing list