Help

Controls

PermLinkWikiLink

Built with Seam

You can find the full source code for this website in the Seam package in the directory /examples/wiki. It is licensed under the LGPL.

Please try out the new component <s:token>, which is available now in SVN and will be included in the Seam 2.1.2.CR1 release, and tell us what you think. This tag is designed to help protect again cross-site request forgery (CSRF). When you place this tag inside of an <h:form>, it produces a random token based on the form's signature and inserts it into a hidden form field named javax.faces.FormSignature. On postback, the token is again generated from the form signature and checked against the javax.faces.FormSignature request parameter. You have a choice whether you want to include the session id in the signature, which would bind the form to the session. The default is to not include the session id. This is a nice solution that gives us independence from the HTTP session but CSRF protection.

What makes this token secure is that it uses the browser's unique identifier as a salt. How does the browser get a unique identifier? The identifier is assigned to the browser using a cookie that is retained for the duration of the browser session. Of course, this means that cookies must be enabled in the browser to submit a form.

I'd like to note that while working on this problem, I determined that client-side state saving can never be protected against CSRF. For that reason, I discourage it's use. The reason it can't be protected is because all the state is owned by the browser. Thus, the server can only assume that the state it is given (i.e., the component tree) must be valid. The server has to hold some sort of counter-state to challenge what it is given, but this is not implemented in JSF (though perhaps we could think about solving that problem as well).

There are three cases when the form submission will be denied:

  • The browser does not send a unique identifier (i.e., cookie)
  • The POST data does not include the form signature
  • The form signature is incorrect

This tag also helps protect against double form posts. A random value is stored on the form component and included in the signature. After a form post happens, the value is cleared from the form component, making it impossible to reproduce the form signature again from the same POST. The form has to be rendered again before it can be submitted.

 

Dan Allen | mojavelinux.com | Author of Seam in Action

17 Replies:
03. Apr 2009, 01:52 CET | Link

That looks so wonderful I wonder why there isn't just a new <s:form/> tag to include that functionality automatically.

 
Dan Hinojosa Seam :: Groovy :: Swing Developer/Consultant/Instructor Albuquerque, NM
03. Apr 2009, 03:41 CET | Link

Awesome Dan! It's like this that come out of the box with Seam (with JSF, this won't help Wicket) that make it a great framework to work with. This is a wonderful security piece, couple it with CAPTCHA and you have a pretty decent first round of security. If you are to use this with ICEfaces it may put a plug in XSS attacks as well because most of their components are required to be in a form anyway. I'll have to play around with this a bit and see what happens.

Solving the client-side state issue you mentioned Dan would be simple enough to solve by doing checksum of the component tree and saving it in the page a scope.

@Daniel I don't think a Seam form would be usable across the board, but it may be. Certainly an interesting idea.

03. Apr 2009, 03:53 CET | Link

The page scope is stored in the browser when using client side state saving, so unfortunate this approach would not solve anything.

03. Apr 2009, 04:11 CET | Link
<blockquote>
_Daniel Hinojosa wrote on Apr 03, 2009 01:52:_<br/>

That looks so wonderful I wonder why there isn't just a new \<s:form/\> tag to include that functionality automatically.
</blockquote>

this is a good suggestion. make it configurable (on/off for token) in components.xml.

this would be similar to the global default queue that RF 3.3.0 introduced with the <rich:queue> tag. so now you don't have to add the eventsQueue, requestDelay attributes to each a4j:support tag, for example.

why wouldn't we want duplicate form submissions to be blocked by default automatically via the s:form tag?
 

required reading: Scala and more Scala... www.artima.com

03. Apr 2009, 05:07 CET | Link

You will this work with ajax requests where the same form is re-submitted several times? Is there a provision to make sure that the javax.faces.FormSignature field is re-rendered each time? Or will the protection not apply for ajax requests?

03. Apr 2009, 05:10 CET | Link

I'm actually reserving <s:form> for another purpose. As you know, <s:link> and <s:button> allow you to create bookmarkable URLs rather than form posts to request a page. I want to make <s:form> follow suit, but that is a topic for a separate post.

 

Dan Allen | mojavelinux.com | Author of Seam in Action

03. Apr 2009, 05:12 CET | Link

The checksum would have to be stored in session scope or some other persistent cache on the server. The idea behind client-side state saving is that you don't burden the server with holding large objects in memory. However, you could fit a lot of checksums into a small space. Care to do a proposal or prototype?

 

Dan Allen | mojavelinux.com | Author of Seam in Action

03. Apr 2009, 05:18 CET | Link

You could put it inside of an ajaxRendered region so that it is automatically updated. Another thing would be to make the inclusion of the render stamp (as I call it) optional, configured via the attribute allowMultipleSubmit="true". I'll give this scenario a quick test and perhaps throw in that feature. Exactly the type of feedback I am looking for.

 

Dan Allen | mojavelinux.com | Author of Seam in Action

03. Apr 2009, 05:35 CET | Link

As long as the UIToken doesn't get decoded, then the form signature stays valid. For instance, if you use ajaxSingle="true" on an input field, then it would not affect the state of the form. If you process the whole form on the server, then the UIToken needs to be in the updates. That is, unless you set the attribute I just mentioned to true, then it doesn't matter.

 

Dan Allen | mojavelinux.com | Author of Seam in Action

03. Apr 2009, 05:41 CET | Link

You know...Having the token in s:form wouldn't be a good idea, and Stuart's post made me think of that. You can essentially have the <s:token> in either a:


<h:form>
   <s:token/>
</h:form>

or a


<a4j:form>
   <s:token/>
</a4j:form>

for AJAX apps, and should work...right?

 
Dan Hinojosa Seam :: Groovy :: Swing Developer/Consultant/Instructor Albuquerque, NM
03. Apr 2009, 05:47 CET | Link

Exactly. Which is why when we introduce <s:form>, it will be for something completely unrelated to standard JSF forms.

 

Dan Allen | mojavelinux.com | Author of Seam in Action

03. Apr 2009, 06:19 CET | Link

allowMultiplePosts attribute added, default false. Please note that the preferred way is to have Ajax update the token.

 

Dan Allen | mojavelinux.com | Author of Seam in Action

03. Apr 2009, 07:17 CET | Link

I have done a quick prototype: JBSEAM-4076. I also attached a patch with the token.xml file so it can be used with facelets

09. Apr 2009, 20:00 CET | Link

Note that it's a good idea to read this knowledge base article before commenting here. We'll continually update the article as we make Seam more secure ootb.

 

Check out my weblog or have a look at the books I wrote.

20. May 2009, 22:55 CET | Link

What would be the impact of this component when running load tests. Load test applications are acting like proxy and replay the post/get requests. How could the load test app know that it should submit what's in the token field?

 

The human knowledge belongs to the world

24. May 2009, 05:50 CET | Link

It depends. If your load testing driver behaves like a browser (i.e., with cookie support) then there should be zero impact since the idea of <s:token> is to ensure that the same browser submitting the form also rendered the form. In a sense, it's just asserting that the negotiation is proper. However, if the load testing driver does not behave like a browser, you will likely need to disable the tag if you find it is blocking requests. In that case, I believe you can use the rendered attribute or (better) surround it in a <c:if> tag to disable for tests.

But really, your load testing should be behaving like a proper browser and hence no impact.

Please follow up if you have trouble or disagree with this assumption (however, please at least look at how the tag works so we can discuss specifics).

 

Dan Allen | mojavelinux.com | Author of Seam in Action

10. Sep 2009, 05:45 CET | Link

Sounds like a awesome idea Dan, by the way I enjoyed your book Seam in Action. Keep up the good work!