Перехватчик Token/TokenSession, ведущий к нулевому указателю на HttpSession

Я работаю над веб-приложением struts2, я обрабатываю уязвимость CSRF с помощью перехватчика токенов.

то, что я делаю, это как успех, так и ошибка, я буду перенаправлять пользователя на ту же страницу, но с ошибкой действия или сообщением об успехе.

<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>

без перехватчика token/tokenSession все работает нормально, но когда я использую перехватчик, я получаю исключение NullPointerException.

трассировка стека

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]

Класс действий

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. что не так с кодом?

  2. не перенаправление на той же странице вызовет проблему (отправленный токен будет отличаться от вновь сгенерированного токена)?

  3. если да, то как мне справиться с этой ситуацией без перенаправления на другую страницу?

person Govinda Sakhare    schedule 24.07.2015    source источник


Ответы (1)


<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>

Вы используете только Token Interceptor. Вместо этого вам нужно запустить весь стек, содержащий Token Interceptor. В противном случае обязательные перехватчики, такие как перехватчик параметров и перехватчик ModelDriven (поскольку вы используете ModelDriven), не будут работать, параметры не будут установлены, и вы получите исключение NullPointerException. Измените его на:

<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>

Также обратите внимание на терминологию, вы ничего не перенаправляете, вы просто отправляете. Перенаправление подразумевает совершенно другой набор проблем, таких как потеря параметров, и это происходит только с результатами redirect и redirectAction.

person Andrea Ligios    schedule 24.07.2015
comment
в то время как действия, которые сами не определяют какие-либо перехватчики-refs, наследуют перехватчики по умолчанию, как только действие объявляет свои собственные перехватчики, оно теряет это автоматическое значение по умолчанию и должно явно указать defaultStack, чтобы использовать его. так что перехватчик токена не является собственным... тогда зачем нам определять перехватчики по умолчанию..?? Поправьте меня, если я ошибаюсь :) :P :) - person goodyzain; 24.07.2015
comment
Я не уверен, что вы спрашиваете: D По умолчанию у вас есть defaultStack для каждого действия. Если вы определяете пользовательский стек, вы можете ссылаться на него из отдельных действий или установить его по умолчанию с помощью тега ‹default-interceptor-ref›, и он будет использоваться каждым действием. В противном случае вы можете указать отдельные перехватчики или даже стеки перехватчиков и для отдельных действий. Если у вас в 99% случаев один и тот же стек, просто определите его по умолчанию и обработайте исключения в действиях. Если у вас много исключений, определите несколько стеков и ссылайтесь на правильный стек по-разному для каждого действия... понятно? - person Andrea Ligios; 24.07.2015
comment
@goodyzain см. в качестве примера: stackoverflow.com/a/27702918/1654265 и stackoverflow.com/a/27295251/1654265 - person Andrea Ligios; 24.07.2015
comment
@AndreaLigios с точки зрения производительности, какой из них лучше между токеном и tokenSession? - person Govinda Sakhare; 24.07.2015
comment
@piechuckerr в ответе, который я связал с вами в предыдущем вопросе ( stackoverflow.com/a/28717589/1654265 ) четко подчеркнута разница между ними, они делают разные вещи; 1) токен отправляет ошибку на каждый запрос после первого, а 2) tokensession проглатывает ошибку и отображает результат первого запроса на каждый запрос после первого. Вы должны решить, какой из них вам нужен, сравнение производительности невозможно, если они делают разные вещи :) - person Andrea Ligios; 24.07.2015
comment
@piechuckerr Кстати, как насчет этого ответа? Это ответило на вопрос, сработало ли это? - person Andrea Ligios; 24.07.2015
comment
@AndreaLigios да, это сработало, я выберу и проголосую, как только закончу тестирование кода. Кстати, большое спасибо, вы решили две мои проблемы за два дня. - person Govinda Sakhare; 24.07.2015