I'm Using MyFaces 2.2.3 with client side state saving + PrimeFaces
After asking how to prevent the re-use of a ViewState in different sessions I was told by BalusC , that I can inject my own CSRF token by override the from renderer to let the value be a CSRF token ,
I'm looking for a solution that wont force me to modify my xhtml pages at all :)
BalusC has suggested a better way to prevent CSRF attack by extending ViewHandlerWrapper
, and it works great, I only had to modify a bit the restoreView
in the following way
public UIViewRoot restoreView(FacesContext context, String viewId) {
UIViewRoot view = super.restoreView(context, viewId);
if (getCsrfToken(context).equals(view.getAttributes().get(CSRF_TOKEN_KEY))) {
return view;
} else {
HttpSession session = (HttpSession) context.getExternalContext().getSession(false);
if (session != null) {
session.invalidate(); //invalidate session so (my custom and unrelated) PhaseListener will notice that its a bad session now
}
try {
FacesContext.getCurrentInstance().getExternalContext().redirect("CSRF detected and blocked"); //better looking user feedback
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
Old solution
I tried without success so far,
Added to faces-config.xml
<render-kit>
<renderer>
<component-family>javax.faces.Form</component-family>
<renderer-type>javax.faces.Form</renderer-type>
<renderer-class>com.communitake.mdportal.renderers.CTFormRenderer</renderer-class>
</renderer>
</render-kit>
Then in CTFormRenderer.java
@Override
public void encodeEnd(FacesContext context, UIComponent arg1) throws IOException {
//how to set form value be a CSRF token?
}
@Override
public void decode(FacesContext context, UIComponent component) {
HttpSession session = (HttpSession) context.getExternalContext().getSession(false);
String token = (String) session.getAttribute(CSRFTOKEN_NAME);
String tokenFromForm = //how to get the value stored in form value attribute because (String) component.getAttributes().get("value"); return null
//check token against tokenFromForm...
}
I don't want to add a custom component to each and every h:form
, instead I want to extend the form
renderer so all my form will have the csrf token
.