I'd like to see a way to implement this for ALL pages, not requiring a custom tag.
I believe this could be done easily using the PreRenderViewEvent to add a hidden form field to store the token in all outbound forms, in combination with a cookie that is sent to the browser, storing a unique private key for that browser session.
Next, use a phase-listener after Restore_View, comparing the request parameter to the restored component value or session. Very similar to the <s:token> component, but as a global solution that could be enabled/disabled via XML config.
The token value increments on each subsequent form submission, and includes a hashed version of the browser's signature (and corresponding public key for the browser's cookie-assigned private key.) The token is compared to either a value stored in ViewState (insecure if using client-side state-saving) or a value stored in the user's session as (an ordered list that can detect repeat or invalid requests.)
Question: how does this affect the back-button?
Note: In order for any cookie-based public key to be assigned to the browser, one MUST assume that the server/client are speaking HTTPS, otherwise any communication of public/private keys will be vulnerable to man-in-the-middle attacks.
"1. When rendered, it assigns a unique identifier to the browser using a cookie that lives until the end of the browser session. This is roughly the browser's private key. The <s:token> tag is used inside of an <h:form> and generates a hidden form field named javax.faces.FormSignature. The form signature is calculated as follows: "