The approach for frustrating XSRF attacks (aka CRSF) I've seen is similar to what you've described here: generate a "transaction token" (nonce); embed it into a form returned by the display JSP (obtained by the initial GET); stash a copy of the token in the HttpSession; then, when the POST is processed, compare the submitted nonce with the stashed copy.
I've been thinking about this issue in relation to solving a particular spam-bot problem we have with JSPWiki, the display tier of which is being migrated to Stripes. Like you, I'd like to solve this in a Stripes-friendly way. There are two issues that need solving: (1) generating and returning the token (I prefer the word "ticket" here) to the user, and (2) processing the submitted ticket. And of course, it needs to be done in a simple and elegant way that is appropriate for Stripes.
I think I have an idea on how to do this. Here's the approach.
First, there's the issue of the ticket. As for (1), this could be done two ways.
a. The Stripes FormTag could be extended to write the ticket name and value out as a hidden field, similar to how the source page is written out today when someone uses the stripes:form tag, or....
b. The ticket could be written out as a cookie with a unique name, and value equal to the ticket value. (It should be possible for the user to have multiple 'transactions' going at once).
In both cases, the ticket name and value would be stashed in the HttpSession. The processing step at time of POST processing (2) would involve checking for the correct value, and if found, removing it from the list of stashed tickets. Failure to find the ticket would cause a checked Exception to be thrown, which could be picked up by an exception handler.
I haven't seen the cookie option discussed in the security community before, so I'm going to solicit some opinions from some security researchers about the viability of this approach. The advantage of using cookies is that no form-rewriting is needed, so you wouldn't need to modify the Stripes FormTag. It's also more "portable" in the sense that it doesn't require developers to use Stripes form tags The disadvantage is that the ticket doesn't travel with the form. I am not sure how big a deal this is, though, because the point of the ticket is that you must have one and it expires.
Now, here's how to wrap everything up with some nice Stripes-like simplicity: use annotations to simply indicate which event methods require tickets. Here's the idea:
@PredecessorEvent(beanclass="com.example.MyActionBean" event="bar")
@HandlesEvent("foo")
public Resolution foo() { ...}
The PredecessorEvent annotation indicates that event handler method "foo" requires the event handler method "bar" of MyActionBean to have previously executed before method "foo" can run. We assume that method foo() forwards to a display JSP that contains the form, though it need not. We can guarantee that "bar" runs before "foo" by using our CRSF tickets. Simple introspection at startup time would determine that there is a predecessor/successor relationship between method "bar" and method "foo," so when "bar" runs we know we need to inject a CRSF ticket.
What would make this all work is a "TransactionInterceptor" that injects the initial ticket for the first method (the GET of the display JSP), and inspects the ticket needed to the execute second method (the POST).
A nice side benefit to this approach is the ability to enforce specific paths through the webapp (you could chain @PredecessorEvent annotations across multiple ActionBeans).
I'd like to get some comments from the Stripes committers about this. I'm happy to work something up as a proof of concept if the approach seems viable.
The approach for frustrating XSRF attacks (aka CRSF) I've seen is similar to what you've described here: generate a "transaction token" (nonce); embed it into a form returned by the display JSP (obtained by the initial GET); stash a copy of the token in the HttpSession; then, when the POST is processed, compare the submitted nonce with the stashed copy.
I've been thinking about this issue in relation to solving a particular spam-bot problem we have with JSPWiki, the display tier of which is being migrated to Stripes. Like you, I'd like to solve this in a Stripes-friendly way. There are two issues that need solving: (1) generating and returning the token (I prefer the word "ticket" here) to the user, and (2) processing the submitted ticket. And of course, it needs to be done in a simple and elegant way that is appropriate for Stripes.
I think I have an idea on how to do this. Here's the approach.
First, there's the issue of the ticket. As for (1), this could be done two ways.
a. The Stripes FormTag could be extended to write the ticket name and value out as a hidden field, similar to how the source page is written out today when someone uses the stripes:form tag, or....
b. The ticket could be written out as a cookie with a unique name, and value equal to the ticket value. (It should be possible for the user to have multiple 'transactions' going at once).
In both cases, the ticket name and value would be stashed in the HttpSession. The processing step at time of POST processing (2) would involve checking for the correct value, and if found, removing it from the list of stashed tickets. Failure to find the ticket would cause a checked Exception to be thrown, which could be picked up by an exception handler.
I haven't seen the cookie option discussed in the security community before, so I'm going to solicit some opinions from some security researchers about the viability of this approach. The advantage of using cookies is that no form-rewriting is needed, so you wouldn't need to modify the Stripes FormTag. It's also more "portable" in the sense that it doesn't require developers to use Stripes form tags The disadvantage is that the ticket doesn't travel with the form. I am not sure how big a deal this is, though, because the point of the ticket is that you must have one and it expires.
Now, here's how to wrap everything up with some nice Stripes-like simplicity: use annotations to simply indicate which event methods require tickets. Here's the idea:
@PredecessorEvent(beanclass="com.example.MyActionBean" event="bar")
@HandlesEvent("foo")
public Resolution foo() { ...}
The PredecessorEvent annotation indicates that event handler method "foo" requires the event handler method "bar" of MyActionBean to have previously executed before method "foo" can run. We assume that method foo() forwards to a display JSP that contains the form, though it need not. We can guarantee that "bar" runs before "foo" by using our CRSF tickets. Simple introspection at startup time would determine that there is a predecessor/successor relationship between method "bar" and method "foo," so when "bar" runs we know we need to inject a CRSF ticket.
What would make this all work is a "TransactionInterceptor" that injects the initial ticket for the first method (the GET of the display JSP), and inspects the ticket needed to the execute second method (the POST).
A nice side benefit to this approach is the ability to enforce specific paths through the webapp (you could chain @PredecessorEvent annotations across multiple ActionBeans).
I'd like to get some comments from the Stripes committers about this. I'm happy to work something up as a proof of concept if the approach seems viable.