I implemented support for Symfony's excellent CSRF protection in forms
today. We had some forms we were rendering field by field, and so of
course we had problems because we weren't calling
$form->renderHiddenFields where we didn't think we had any. No
problem, I've taken care of that, and I appreciate what a great
feature this is to have "in the box" in Symfony.

But I still had problems with a few actions. These are cases where I
need the user to supply some information on the first pass, such as
uploading several images, and then provide more details on a second
pass (you don't want to edit descriptions of images you aren't even
looking at yet).

My solution to this in the past has been to use two different form
classes (often subclasses of the same parent), with different but
compatible field sets. The first form takes a subset of the fields
required for the second, so everything works. I use an extra
"first_pass" parameter to clue in the second form that it shouldn't
generate huffy validation errors, just quietly request all the
as-yet-missing info. I suspect this is a fairly common pattern.

Unfortunately I ran into a snag with CSRF. Turns out the CSRF token is
built like this:

md5($secret.session_id().get_class($this));

There are several pieces used here to arrive at the key that's hashed:

The secret, unique to the application as a whole (usually)
The user's PHP session ID
The form class

The third one is what bit me. I worked around it by removing
.get_class($this) in my own override of this method in the form
classes where I need to be able to submit data first to one form class
and then to another.

This leads to some questions:

1. Why include the form class in the key? The number of form classes
in a particular application is relatively small. This only helps when
form data for a currently live session has already been intercepted
(which would mean you probably have the cookies too anyway) AND the
form you're hoping to CSRF is a different form. That seems like a
pretty narrow case, and it causes problems for legitimate applications
like mine.

2. Just for curiosity: why have an application secret either? The PHP
session ID is already unique, and you can't discover it unless you
have the user's cookie for the Symfony-based site, which you won't if
you're just dumping carefully crafted links and forms into an
unrelated site to go phishing. I guess there's a small risk if you're
using an incrementing MySQL ID as the session ID and it's very early
in the lifetime of the site. The application secret certainly isn't
hurting anything, I'm just curious about this part.

-- 
Tom Boutell
P'unk Avenue
215 755 1330
punkave.com
window.punkave.com

-- 
You received this message because you are subscribed to the Google Groups 
"symfony developers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/symfony-devs?hl=en.

Reply via email to