3

We have been securing our backing bean methods using a custom @Secure interceptor to prevent forged invocations of the method.

But recently, it hit me that these methods are not reachable if the component invoking the action is not rendered. It is my understanding that JSF will generate the view, and if the component is not rendered based on permissions (e.g. EL with isUserInRole), then any forged POST with that component as the source will not fire because the component will not be found in the restored view. Is this correct?

Essentially, any forgery would have to have a compromised and current JSESSIONID and perhaps even ViewState depending on whether they needed the same view.

Can someone please confirm that my assumptions are correct and, if possible, point me to a place in the spec?

Thanks

MarkL
  • 477
  • 4
  • 11
  • I think I may have found my answer here, just don't know if its spec or not: http://stackoverflow.com/questions/6524788/how-to-properly-use-isuserinrolerole – MarkL Jan 09 '14 at 19:28

2 Answers2

3

Ok,I think I have confirmation that actions for non-rendered components are indeed not reachable according to the spec.

Section 2.2.2 of the specification states:

During the Apply Request Values phase, the JSF implementation must call the processDecodes() method of the UIViewRoot of the component tree.[P1-end] This will normally cause the processDecodes() method of each component in the tree to be called recursively, as described in the Javadocs for the UIComponent.processDecodes() method.

It also states:

During the decoding of request values, some components perform special processing, including: Components that implement ActionSource (such as UICommand), which recognize that they were activated, will queue an ActionEvent. The event will be delivered at the end of Apply Request Values phase if the immediate property of the component is true, or at the end of Invoke Application phase if it is false.

So ActionSource components will only queue an action if they are processed according to processDecodes. Looking at the javadoc for that:

Perform the component tree processing required by the Apply Request Values phase of the request processing lifecycle for all facets of this component, all children of this component, and this component itself, as follows.

  • If the rendered property of this UIComponent is false, skip further processing.

So the first check must be whether or not the component is rendered, and if not, skip the rest. The ActionSource is never queued and the action never invoked.

One more note, it does appear that ViewState is only reliable for CSFR prevention as of JSF 2.2 per the spec:

https://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-869

Previous implementations were apparently too predictable and didn't cover GET requests. The spec now requires this.

So, while it may still be a good practice to secure the server side as well, it does appear it is sufficient to control rendering of the ActionSource component.

MarkL
  • 477
  • 4
  • 11
0

JSESSIONID is definitely needed. but that can be easily accessed if a user logged in - I am talking about a case when the user is logged in, but supposedly doesn't have access to the specific method.

The other part is more tricky. If the state is stored on client side, then that can be forged. Beside, there is mechanisms to provide direct link to the actions and pages - like pretty or simple link. If the method is exposed in any of those ways, it should be restricted.

I would secure them to prevent future headaches of constantly monitoring which method is exposed in what way - just imagine if you wanted to add a REST or SOA interface for the application.

Arash
  • 11,697
  • 14
  • 54
  • 81
  • I agree, I think it would be best to preemptively secure it for future REST services and also understand JSESSIONID is required for any forgery request in this case. I also don't use client state saving, but admit I hadn't thought of that. I guess I'm looking for confirmation that if I have a method like "save" on a backing bean, and the only place I call that is via a conditionally rendered command button, is it safe to assume its not reachable unless the button is rendered? Is there a place in the spec that talks about this? – MarkL Jan 07 '14 at 02:49
  • BTW: the reason I think it would not be enough to use my own JSESSIONID to "elevate" my privileges is that I would have to also provide a ViewState id that associates with a restored view with the button, which won't happen if I don't have the proper role. – MarkL Jan 07 '14 at 02:51
  • Another point is how you prevent the button from rendering. If the render property is false, the button is still there in the tree, and I think one can forge an invocation. On the other hand if a c:if is used, then it is not in the tree at all and invocation fails. – Arash Jan 08 '14 at 15:54
  • Hmm, I'm not saying you are wrong, but I think actually the button is not in the view tree if it rendered evaluates to false. At least that's the trust of my presumption. I'll put together a test and report back. – MarkL Jan 09 '14 at 18:50
  • I confirmed that if create a page with a conditional button and let the button render, I can get the same page with appropriate URL parameter with a GET. If I then change the condition so the button does not render, the action is NOT invoked. If I examine the ViewRoot via FacesContext, I can confirm that you are right, the button is still there, but not sure this is the same as the tree and/or validation that JSF does in the lifecycle. In short, I can confirm that at least with Mojarra, the action is not reachable by forging the request. I just don't know if this is Mojarra or a spec thing. – MarkL Jan 09 '14 at 19:25