1

I have a hidden field on every page inside <s:form> representing a security token (Spring security) which is automatically initialized and maintained by the security framework (not Struts).

Hence, a getter and a setter for this field are not required in the corresponding action class.

Since there are no getter and setter for this field in the action class, it produces a message quite unnecessarily on the server terminal something like the following.

SEVERE: Developer Notification (set struts.devMode to false to disable this message): Unexpected Exception caught setting '_csrf' on 'class actions.CategoryAction: Error setting expression '_csrf' with value ['673b1d7a-6ab2-4241-86b9-0ccfe8094356', ]

This message itself can just be suppressed by disabling struts.devMode either in web.xml or struts.xml (or even in struts.properties).

But is there a way to bypass this field so that it does not even reach the action class? Simply because the value of this field is going to be used by the Spring security framework and not Struts. It is not needed by Struts at all.


One of the action classes (it is just a test case):

@Namespace("/admin_side")
@ResultPath("/WEB-INF/content")
@ParentPackage(value = "struts-default")
public final class TestAction extends ActionSupport implements Preparable
{
    public TestAction() {}

    //Some validators as required.
    @Action(value = "AddOrUpdate",
        results = {
            @Result(name=ActionSupport.SUCCESS, type="redirectAction", params={"namespace", "/admin_side", "actionName", "Test"}),
            @Result(name = ActionSupport.INPUT, location = "Test.jsp")},
        interceptorRefs={
            @InterceptorRef(value="paramsPrepareParamsStack", params={"params.acceptParamNames", "param1, param2", "validation.validateAnnotatedMethodOnly", "true"})
        })
    public String insertOrUpdate(){
        // Do something. Add or update a row to the database (one at a time).
        return ActionSupport.SUCCESS;
    }

    @Action(value = "Test",
    results = {
        @Result(name = ActionSupport.SUCCESS, location = "Test.jsp"),
        @Result(name = ActionSupport.INPUT, location = "Test.jsp")},
    interceptorRefs = {
        @InterceptorRef(value = "paramsPrepareParamsStack", params = {"params.acceptParamNames", "param1, param2", "validation.validateAnnotatedMethodOnly", "true"})})
    public String load() throws Exception {
        //This method is just required to return an initial view on page load.
        return ActionSupport.SUCCESS;
    }

    @Override
    public void prepare() throws Exception {}
}

The Struts form which is bound to the action class above.

<s:form namespace="/admin_side" action="Test" validate="true" id="dataForm" name="dataForm">

    <!--Some Struts elements as required like <s:textfield>-->

    <s:hidden name="%{#attr._csrf.parameterName}" value="%{#attr._csrf.token}"/>
    <!--This hidden field is automatically initialized to a random, hard-to-guess string-->
    <!--Its name is _csrf which is mandatory by design, AFAIK.-->

    <s:submit value="Submit" action="AddOrUpdate"/>
    <!--The action of this button is mapped to insertOrUpdate() method in the action class.-->
    <!--When this button is clicked, the insertOrUpdate() method in the action class is invoked.-->
<s:form>
Tiny
  • 27,221
  • 105
  • 339
  • 599
  • Why not just to add this parameter to `excludeParams` parameter pattern of the `params` interceptor? – Roman C Feb 05 '14 at 19:44
  • I have already listed **only necessary** parameters to the `acceptParamNames` property of the `params` interceptor in which this parameter, `_csrf` has not been listed. In addition to this, I have also tried adding `_csrf` to `excludeParams` but that didn't make a difference either leaving the same message. – Tiny Feb 05 '14 at 19:56
  • What is the name of this hidden field? Instead of `_csrf` it can be also `token` – Kamil Chaber Feb 05 '14 at 21:26
  • @KamilChaber : The name of this hidden field is `_csrf` which is mandatory to have that name (by design). – Tiny Feb 06 '14 at 05:41
  • If I understood you correctly, value of the expression `%{#attr._csrf.parameterName}` equals `_csrf`, right? – Kamil Chaber Feb 07 '14 at 15:12
  • @KamilChaber : Yes correct. The OGNL expression, `%{#attr._csrf.parameterName}` returns `_csrf` which is the name of the hidden field. It is a dynamic name. I can also be given a static name just like `name="_csrf"`. – Tiny Feb 07 '14 at 15:15
  • Maybe try to escape `_ (underscore)` in `acceptParamNames` parameter in `params` interceptor. Try the following: `@InterceptorRef(value = "paramsPrepareParamsStack", params = {"params.acceptParamNames", "param1, param2, \_csrf", "validation.validateAnnotatedMethodOnly", "true"})})` – Kamil Chaber Feb 07 '14 at 15:27
  • @KamilChaber : It does not work even after escaping, when the parameters interceptor is used, `paramsPrepareParamsStack`. It however, works fine without escaping, when `defaultStack` is used. Therefore, escaping `_` should not be necessary. This led me to a [new question](http://stackoverflow.com/q/21607121/1391249). – Tiny Feb 07 '14 at 15:36

1 Answers1

0

I have tried this in non-struts applications ,but what you can do is set the field as disabled and hidden.

As far as I know,

Elements with Disabled attribute are not submitted or you can say their values are not posted.

And since <s:from> is expanded as <form> eventually, it will probably work. I don't know how will security framework react to it, but do let me know if it works for ya :)

UPDATES

I don't know if this will cause some performance issue.. But I think there is a work around.

What we can do is write an interceptor , access the value-stack and pop the variable from value-stack, so the variable wont reach action class. I am sure this will work.This is the final-way I can think off.. So Fingers crossed.

DarkHorse
  • 2,740
  • 19
  • 28
  • I have tried disabling the hidden element but doing so, prevents the element itself from being submitted. The value of this field is required by the security framework to guard against CSRF attacks. If this field is not submitted (or its value is not matched) then, access to the requested resource is severely forbidden causing the 403 error, access denied. – Tiny Feb 06 '14 at 05:39
  • @Tiny I thought so.. security framework might fail... But can we have look at your form? Need to see you form setup and also the corresponding action class.. especially categoryAction.. – DarkHorse Feb 06 '14 at 06:01