Web programming and a different "type" problem

Dave Cole djc at object-craft.com.au
Tue Apr 29 20:12:24 EDT 2003


> On Tue, 2003-04-29 at 07:50, Dave Cole wrote:
> > Albatross solves this yet another way.  As input tags are processed by
> > the template interpreter the form tag accumulates a summary of all the
> > input fields.  When the form is closed the summary is then pickled,
> > MD5 signed with a secret, compressed, and base64 encoded in a hidden
> > field.
> 
> You mean, it takes the expected names?  Like a form:
> 
> Object 1: <input type=checkbox name="id*" value=1>
> ...
> Object 4: <input type=checkbox name="id*" value=4>
> 
> You create a hash of (in this small form) just "id*", and so confirm
> the user isn't sending extra fields, or changing field names?

Sort of.

> Seems a little odd... or are you doing something else?  There's
> always the issue of the security of hidden fields, but that's kind
> of a different issue.

With Albatross templating the form would look like this:

<al-form>
 <al-input type="checkbox" name="id" value="1" list>
 <al-input type="checkbox" name="id" value="4" list>
</al-form>

Just to restate the problem:

When the browser sends a response to the above form (assuming you
have a submit input somewhere) it can send 0, 1, or 2 values for the
"id" field.  With the base cgi.py handling you have to do something
like this:

   fields = cgi.FieldStorage()
   if fields.has_key('id'):
       if type(fields['id']) is type([]):
           for field in fields['id']:
               process(field.value)
       else:
           process(fields['id'].value)

What you really want to be able to do is something like this
regardless of how many values were submitted by the browser:

   for value in request.fields['id']:
       process(value)

So what Albatross does is allow (require) you to specify when a field
should return a list.  If you build a form which contains multiple
inputs with the same name ("radio" is an obvious exception) then it
will raise an exception if you do not use the "list" attribute on all
of the instances of the field in the form.

In our experience you can get subtle and annoying bugs in your
application as a result of incorrect handling of fields which
sometimes return multiple values.

How Albatross handles the problem:

When the template interpreter sees the <al-form> it starts recording
the types of all <al-input> tags.  Each <al-input> is checked for
multiple instances and consistent declaration of "list" attribute.
Any error raises and exception.  This allows programming errors to be
caught during development, not when the application goes live.

When the </al-form> tag is processed, the record of fields is encoded
into a hidden field called __albform__.  The field value is MD5 signed
by combining the encoded value with a server side secret and the sign
is combined with the __albform__ value.

When the browser posts a response to the form the __albform__ value is
checked for tampering.  If the check fails the __albform__ value is
discarded.  If the __albform__ value is OK it is used to process the
rest of the fields in the browser request.

If the request was OK fields which were declared with the "list"
attribute will always yield a list of values.  In the above example
the 'id' field will be set to a list of 0, 1, or 2 values.  Fields
which were not declared as "list" will be set to None if they are not
present in the browser request.

Currently one downside to this is that when the __albform__ value is
not present, the request merging falls back to a mode where it merges
all values present in the request in the form that they are present.
This means that it is more a convenience feature than a security
feature :-)

- Dave

-- 
http://www.object-craft.com.au




More information about the Python-list mailing list