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.