javastruts2csrf-protectionstruts2-interceptorsinterceptorstack

Token/TokenSession interceptor leading to nullpointer on HttpSession


I am working on struts2 web application, I am handling CSRF vulnerability by using token interceptor.

what I am doing is on success as well as error, I will be redirecting user to the same page but with action error or success message.

<action name="saveApplicationForm" class="action.ApplicationFormAction" 
      method="saveApplicationForm">
        <interceptor-ref name="token" />
        <result name="invalid.token" type="tiles">applicationForm.tiles</result>    
        <result name="input" type="tiles">applicationForm.tiles</result>
</action>

without token/tokenSession interceptor everything is working fine, but when I am using interceptor I am getting NullPointerException.

stacktrace

java.lang.NullPointerException: null
at action.ApplicationFormAction.saveApplicationForm(ApplicationFormAction.java:218) ~[ApplicationFormAction.class:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_67]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_67]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_67]
at java.lang.reflect.Method.invoke(Method.java:606) ~[na:1.7.0_67]
at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:450) [xwork-core-2.3.16.3.jar:2.3.16.3]
at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:289) [xwork-core-2.3.16.3.jar:2.3.16.3]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:252) [xwork-core-2.3.16.3.jar:2.3.16.3]
at org.apache.struts2.interceptor.TokenInterceptor.handleValidToken(TokenInterceptor.java:193) [struts2-core-2.3.16.3.jar:2.3.16.3]
at org.apache.struts2.interceptor.TokenInterceptor.handleToken(TokenInterceptor.java:154) [struts2-core-2.3.16.3.jar:2.3.16.3]
at org.apache.struts2.interceptor.TokenInterceptor.doIntercept(TokenInterceptor.java:142) [struts2-core-2.3.16.3.jar:2.3.16.3]
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) [xwork-core-2.3.16.3.jar:2.3.16.3]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) [xwork-core-2.3.16.3.jar:2.3.16.3]
at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54) [struts2-core-2.3.16.3.jar:2.3.16.3]
at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:562) [struts2-core-2.3.16.3.jar:2.3.16.3]
at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77) [struts2-core-2.3.16.3.jar:2.3.16.3]
at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99) [struts2-core-2.3.16.3.jar:2.3.16.3]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [catalina.jar:7.0.63]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:7.0.63]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) [catalina.jar:7.0.63]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) [catalina.jar:7.0.63]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505) [catalina.jar:7.0.63]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170) [catalina.jar:7.0.63]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) [catalina.jar:7.0.63]
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:957) [catalina.jar:7.0.63]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) [catalina.jar:7.0.63]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423) [catalina.jar:7.0.63]
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079) [tomcat-coyote.jar:7.0.63]
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:620) [tomcat-coyote.jar:7.0.63]
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318) [tomcat-coyote.jar:7.0.63]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_67]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_67]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-coyote.jar:7.0.63]
at java.lang.Thread.run(Thread.java:745) [na:1.7.0_67]

Action class

public class ApplicationFormAction extends ActionSupport implements ModelDriven<ApplicationFormBean>, SessionAware
{
   private Map<String, Object> session; 
    // getter and setter

   public String saveApplicationForm()
   {
      // getting nullpointer here
     ApplicationFormBean sessApplicationFormBean = (ApplicationFormBean) this.session.get(SESSION_KEY_APPLICANT);
   }

}
  1. what is wrong with the code?

  2. ain't redirecting on same page will cause problem(submitted token will be different from newly generated token)?

  3. if yes then how should I handle this situation without redirecting to other page?

Solution

  • <action name="saveApplicationForm" class="action.ApplicationFormAction" 
          method="saveApplicationForm">
            <interceptor-ref name="token" />
            <result name="invalid.token" type="tiles">applicationForm.tiles</result>    
            <result name="input" type="tiles">applicationForm.tiles</result>
    </action>
    

    You are running only the Token Interceptor. You need to run an entire stack instead, containing the Token Interceptor. Otherwise mandatory interceptors like Parameter Interceptor and ModelDriven Interceptor (since you're using ModelDriven) won't run, parameters won't be set and you will get NullPointerException. Change it to:

    <action name="saveApplicationForm" class="action.ApplicationFormAction"
          method="saveApplicationForm">
            <interceptor-ref name="defaultStack" />
            <interceptor-ref name="token" />
            <result name="invalid.token" type="tiles">applicationForm.tiles</result>    
            <result name="input" type="tiles">applicationForm.tiles</result>
    </action>
    

    Also pay attention to the terminology, you are not redirecting anything, you're just dispatching. Redirecting implies a whole different set of problems like lost of parameters, and it happens only with redirect and redirectAction results.