9

I have a JSF application that uses Mojarra 2.2.9 and is deployed on WebSphere 8.5.5.4 on clustered environement and javax.faces.STATE_SAVING_METHOD is set to client.

Even though all my application beans are request scoped, sometimes when the user session is valid and the user is doing post request on a page he gets ViewExpiredException. What may be causing this issue and how can I solve it? Will changing the javax.faces.STATE_SAVING_METHOD to server solve it? If so, what is the impact of doing this on memory?

Also, does this have anything to do with cluster environement and maybe there's some missing configuration on the Websphere that will solve the issue?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Mahmoud Saleh
  • 33,303
  • 119
  • 337
  • 498
  • To exclude the obvious, do you have `` in `web.xml`? – BalusC Jan 30 '16 at 14:12
  • @BalusC, no i don't have it – Mahmoud Saleh Jan 30 '16 at 16:24
  • @BalusC, if i configured session affinity in websphere, will i still have to add this tag in the web.xml of my application ? – Mahmoud Saleh Jan 31 '16 at 05:58
  • @BalusC Is it possible to get a ViewExpiredException when using client state saving? I am curious because I always thought it was impossible. – hwibell Feb 24 '16 at 06:12
  • 1
    @hwibell: by default on a single server it's impossible. But in a cluster it can be thrown when the view is serialized in one server and deserialized in other server without having configured the app as distributable and having set [`jsf/ClientSideSecretKey`](http://stackoverflow.com/q/28231372) (but that would have caused a "MAC did not verify" error, not a VEE, so it's kind of weird here). On a single server it can also be thrown if `com.sun.faces.clientStateTimeout` is set, but this is unlikely the case here. – BalusC Feb 24 '16 at 07:50
  • MahmoudS, perhaps you just need to set `jsf/ClientSideSecretKey`? I would only wonder why you got a ViewExpiredException instead of "ERROR: MAC did not verify". – BalusC Feb 24 '16 at 07:55
  • @BalusC, will you are correct i am getting the error 'mac did not verify' in the log file but didn't thought that this is a jsf exception, and i still get it even after adding to the application web.xml, is the only solution to this error is changing the state saving method to server ? and why it's appearing in the first place – Mahmoud Saleh Feb 25 '16 at 11:53
  • @BalusC Thanks for that information. Good to know :D – hwibell Feb 25 '16 at 19:09

2 Answers2

13

This will happen if the client side state is encrypted by one server and decrypted by other server and the servers don't use the same AES key for this. Normally, you should also have seen below warning in server log:

ERROR: MAC did not verify

You need to ensure that you have set jsf/ClientSideSecretKey in web.xml with a fixed AES key, otherwise each server will (re)generate its own AES key during startup/restart (which is used during encrypting view state).

<env-entry>
    <env-entry-name>jsf/ClientSideSecretKey</env-entry-name>
    <env-entry-type>java.lang.String</env-entry-type>
    <env-entry-value>[AES key in Base64 format]</env-entry-value>
</env-entry>

You can use this snippet to generate a random AES256 (32bit) key in Base64 format.

KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256); // Use 128 for 16bit key.
String key = Base64.getEncoder().encodeToString(keyGen.generateKey().getEncoded());
System.out.println(key); // Prints AES key in Base64 format.

In case you get Java Security: Illegal key size or default parameters? error, install the cryptography extension as instructed in the link, or else generate a random AES128 (16bit) key instead.

After having the key, make absolutely sure you don't publish/opensource your key.

Further you also need to ensure you have added <distributable /> tag to web.xml so JSF will perform more agressive session dirtying and the HTTP sessions (including view scoped beans themselves!) are properly synced across servers.

Another probable cause of ViewExpiredException with client side state saving is that you've set the Mojarra-specific context param com.sun.faces.clientStateTimeout in web.xml which represents the time in seconds before an incoming client side state is considered expired. This is however unlikely the case here as that context param has a rather self-explaining name which you would have spotted by just glancing over web.xml.

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • ,After adding this parameter, i keep getting the error : `java.security.InvalidKeyException: Illegal key size` even after i used this page to generate AES 128 bit https://asecuritysite.com/encryption/keygen – Mahmoud Saleh Feb 28 '16 at 09:33
  • The page generates a 32bit key (AES256). You may need to have the cryptography extension in your JRE: http://stackoverflow.com/q/6481627 If this is not an option, choose a shorter key e.g. 16bit (AES128). Use the code snippet at bottom of this answer http://stackoverflow.com/a/28277433 to generate your own. You only need to replace `256` by `128`. – BalusC Feb 28 '16 at 09:57
  • i am using java 6 is there's any replacement for the Base64 of java 8 ? – Mahmoud Saleh Feb 28 '16 at 10:07
  • i used the `org.apache.commons.codec.binary.Base64` with the following code and it works fine: `KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(128); byte[] encodedBytes = Base64.encodeBase64(keyGen.generateKey().getEncoded()); String key = new String(encodedBytes);` – Mahmoud Saleh Feb 28 '16 at 10:18
  • @BalusC, client side state saving method + constant ClientSideStateKey allows CSRF attack. Am I right? – guest Nov 20 '19 at 01:09
  • 1
    @guest: nope, it allows full attacks. That's why my answer says *"After having the key, make absolutely sure you don't publish/opensource your key."* – BalusC Nov 20 '19 at 09:41
  • @BalusC, that for sure, but I am talking about situation, when somebody doesn't know my key. Hacker can check in Chrome Developer Tools what form data and what ViewState is send when clicking "Delete account" button. If ViewState doesn't contain any specific data for current user (because user specific data are kept in session), this ViewState will be universal. Then Hacker prepares form which send exactly the same data and trick someone to click this. Hacked! – guest Nov 20 '19 at 09:58
  • @guest: the view state doesn't contain this information at all. – BalusC Nov 20 '19 at 09:59
  • @BalusC, My point is that client side state saving method is generally vulnerable to CSRF. – guest Nov 20 '19 at 10:02
  • @guest: nope. Related reading: https://stackoverflow.com/q/7722159 and probably also https://stackoverflow.com/q/2397952. – BalusC Nov 20 '19 at 10:08
  • @BalusC, I read those questions and they are mainly about server state saving method. I checked request generated by clicking button on JSF page (with client side saving method) and I see form was send with field "javax.faces.ViewState". Nothing random here. So I can copy whole request and rerun it with the same result. – guest Nov 20 '19 at 10:59
  • @guest: and that's not a CSRF attack. – BalusC Nov 20 '19 at 11:16
  • @BalusC, en.wikipedia.org/wiki/Cross-site_request_forgery "In a CSRF attack an innocent end user is tricked by an attacker into submitting a web request that they did not intend". Hacker prepares request data (he knows component ids, he knows valid ViewState). Hacker tricks user to send hidden html form to our JSF site with this prepared data. Because user is logged in, request succeeds. – guest Nov 20 '19 at 12:03
  • @BalusC is JSF session dirtying & syncing mechanism you mentioned when declaring app as `distributable`, part of the JSF specs or implementation specific? Can you provide more info on this? – tsobe Jan 21 '20 at 10:22
  • @sevteen: `web.xml` is part of Servlet API and it's usually implemented by your target server. I know you're using WebSphere, in that case refer its documentation on clustering. For example: http://publib.boulder.ibm.com/wasce/V2.0.0/en/clustering.html – BalusC Jan 21 '20 at 10:30
  • @BalusC yes I'm aware that it's part of Servlet API, but you mentioned "JSF will perform more agressive session dirtying and the HTTP sessions", so that's why I thought maybe JSF is doing something on top of Servlet containers – tsobe Jan 21 '20 at 10:42
  • @BalusC I view `web.xml` as a place for application developer configuration that should not be changed between deployments, such as what servlets to run, what the available application roles are, etc. Everything that is deployment-specific belongs in the context, such as database connection, ldap authentication, email server. The `jsf/ClientSideSecretKey` parameter is deployment-specific (could change for every deployment), and based on my thinking, does not belong in `web.xml`. Is there some way of defining it in the context instead of `web.xml`? – Pixelstix Mar 17 '21 at 14:02
  • @Pixelstix: All `` can be (re)defined in server's JNDI. – BalusC Mar 17 '21 at 14:06
  • @BalusC: Aah, thanks! I had never used that before. In Tomcat, I believe that would result in: `` based on [Tomcat JNDI docs](https://tomcat.apache.org/tomcat-8.5-doc/jndi-resources-howto.html). See also [Tomcat context docs](https://tomcat.apache.org/tomcat-8.5-doc/config/context.html#Environment_Entries). – Pixelstix Mar 17 '21 at 14:26
2

You must have the distributable tag in your web.xml as mentioned by balusc

A. Shaheen
  • 105
  • 13
  • 1
    what's the use of this tag, would you please give little details ? – Mahmoud Saleh Jan 31 '16 at 16:15
  • 1
    This tag tells your application server to replicate HTTP sessions, this guide is for JBoss App server http://blog.akquinet.de/2012/06/21/clustering-in-jboss-as7eap-6/ I think the same may be applicable for Web Sphere. – A. Shaheen Jan 31 '16 at 17:45
  • But as far as i understand session replication, that it works when one of the servers is done then the load balancer redirect the user to another server then copy the session data if session replication is enabled, but in my case all the servers are up and running and the user session is valid – Mahmoud Saleh Feb 07 '16 at 13:59