本文于2016年4月底完成,发布在个人博客网站上。
考虑个人博客因某种原因无法修复,于是在博客园安家,之前发布的文章逐步搬迁过来。
诡异的问题
AppScan扫描报告中提示,Web服务器返回js
、css
、png
、jsp
页面的HTTP响应中缺少安全头部。HTTP的安全头部包括HTTP Strict Transport Security
、X-Frame-Options
、X-Content-Type-Options
、X-XSS-Protection
、Content-Security-Policy
。
网上资料很多,于是参照资料修改$CATALINA_BASE/conf/web.xml
,增加相关配置,如下是样例:
httpHeaderSecurity
org.apache.catalina.filters.HttpHeaderSecurityFilter
true
httpHeaderSecurity
/*
本以为这样修改之后问题就解决了,所以也没用浏览器的调试面板去仔细检查Web服务器响应数据的HTTP头部;但天不遂人愿,事情并没有如预想的方向发展。
在稍后的一份AppScan扫描报告中,居然又看到了Web服务器返回的HTTP响应缺少安全头部的提示。不过这次稍有区别,报告中只提示jsp
页面的访问存在问题。于是使用浏览器的调试面板仔细查看Web服务器返回的响应信息,发现Web服务器返回js
、css
、png
时,在HTTP响应中增加了必要的头部,如下所示:
Cache-Control:private
Content-Type:image/png
Date:Sun, 10 Apr 2016 13:16:26 GMT
Expires:Thu, 01 Jan 1970 08:00:00 CST
Server:Apache-Coyote/1.1
Strict-Transport-Security:max-age=0
Transfer-Encoding:chunked
X-Content-Type-Options:nosniff
X-Frame-Options:DENY
X-XSS-Protection:1; mode=block
这说明安全头部的配置生效了,但诡异的是jsp
页面的响应中并没有相应增加安全头部,如下所示,导致AppScan报告中Web服务器返回的HTTP响应缺少安全头部问题依然存在。
Content-Type:text/html;charset=UTF-8
Date:Tue, 24 May 2016 16:18:30 GMT
Server:Apache-Coyote/1.1
Transfer-Encoding:chunked
同部门内有一个A项目,这个项目有10年开发、维护的历史,历经公司安全红线多轮整改,项目成员积累了相当丰富的斗争经验,在处理AppScan扫描报告上也有相当的经验。于是就安全头部的整改方法咨询A项目的MDE,希望可以获得关键信息。
A项目的MDE为人很爽快,介绍了他们的经验,总结下有如下几点:
- A项目在整改AppScan扫描问题时,确实遇到过类似的问题,解决的方法是给响应增加安全头部。
- 但A项目使用了自定义的过滤器来给HTTP响应增加安全头部,并没有使用Apache Tomcat官方提供的过滤器,原因是A项目使用的Tomcat版本太低,出于业务原因暂不好升级。
- A项目增加自定义的过滤器之后,“Web服务器返回的HTTP响应缺少安全头部”就从AppScan扫描报告中消失了。
但坏消息是A项目团队没有遇到过前述的问题,自然没有处理类似问题的经验可供参考。这就诡异了,为什么Web服务器对jsp
的响应没有增加安全头部呢?
分析过程
当前的项目使用了Spring+Struts2+iBatis,从技术组合上可以说非常传统,但在技术应用上存在很大不同。为了描述方便,下面把存在问题的项目称为B项目。
检查项目配置
重温项目的配置情况。
Struts2的配置
Struts2在web.xml中的配置如下:
struts2
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
struts2
/*
简化后的struts.xml配置文件,内容如下:
/error.jsp
{1}.jsp
通用Action类,简化后的MainAction
代码如下
import com.opensymphony.xwork2.ActionSupport;
public class MainAction extends ActionSupport {
private static final long serialVersionUID = 928135783255954591L;
@Override
public String execute() throws Exception {
return ActionSupport.SUCCESS;
}
}
粗看下来,似乎没有什么不妥的地方。
安全头部的配置
依照文档,重新检查$CATALINA_BASE/conf/web.xml
文件中的配置,如下:
httpHeaderSecurity
org.apache.catalina.filters.HttpHeaderSecurityFilter
true
httpHeaderSecurity
/*
没看出来什么特别的地方,而官方文档对HttpHeaderSecurityFilter
的使用也没有特别的说明,那是不是HttpHeaderSecurityFilter
的实现代码中有玄机?
找到HttpHeaderSecurityFilter
类的代码,如下是增加头部的实现。
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (response instanceof HttpServletResponse) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
if (response.isCommitted()) {
throw new ServletException(sm.getString("httpHeaderSecurityFilter.committed"));
}
// HSTS
if (hstsEnabled && request.isSecure()) {
httpResponse.setHeader(HSTS_HEADER_NAME, hstsHeaderValue);
}
// anti click-jacking
if (antiClickJackingEnabled) {
httpResponse.setHeader(ANTI_CLICK_JACKING_HEADER_NAME, antiClickJackingHeaderValue);
}
// Block content type sniffing
if (blockContentTypeSniffingEnabled) {
httpResponse.setHeader(BLOCK_CONTENT_TYPE_SNIFFING_HEADER_NAME,
BLOCK_CONTENT_TYPE_SNIFFING_HEADER_VALUE);
}
// cross-site scripting filter protection
if (xssProtectionEnabled) {
httpResponse.setHeader(XSS_PROTECTION_HEADER_NAME, XSS_PROTECTION_HEADER_VALUE);
}
}
chain.doFilter(request, response);
}
代码很简单,没发现对jsp的访问有做过什么特别的处理。
对页面访问的影响
依据前述配置,页面访问流程如下所示:
- 浏览器请求页面时,Web服务端的Struts2拦截页面访问请求;
- Web服务端的通用Action接收请求,并将请求重定向至对应的jsp页面;
- 由于没有使用Action向页面传递数据,所以开发人员需要在页面上使用ajax方式向Web服务端请求业务数据;
进一步分析
仔细回想了A项目的特点,以及与B项目的差异点。
A项目也使用了Spring+Struts的组合,但和B项目有个显著不同点,B项目是Struts2的重度使用用户,项目中的jsp
全部使用action做了包装,用户在地址栏看不到jsp
结尾的URL。
而B项目虽然使用了Spring+Struts的组合,但实际上仅仅使用了Struts2提供的国际化和s标签,代码中定义的Action仅用于转发请求至jsp
,用户在浏览器的地址栏里可以明确的看到当前页面的jsp
文件名和路径。
如下是A项目struts.xml文件中action后缀的配置
如下是B项目struts.xml文件中action后续的配置
问题在于A项目并没有遇到B项目现在遇到的问题。
分析到这里,尝试调整struts.xml的配置,去掉配置中的jsp
,如下所示
这样action后缀的配置和A项目保持一致。
重启应用之后,使用Google Chrome提供的调试面板,检查Web服务器对jsp
页面的响应,发现居然有HTTP安全头部。这说明,action后缀的配置对安全头部的生成有影响,但具体什么影响还未知,并且出于技术原因,目前并不能调整action后缀的配置。因此这问题还不算完,需要继续分析。
依据J2EE规范中Filter和Servlet的定义,我们知道Filter在执行时需要等待Servlet完成处理并写出响应后才会逐个返回,因此观察Servlet的运行栈,可以看到Web请求的处理路径。既然调整action后缀的配置对安全头部的生成有影响,那么说明不同的配置条件下,jsp的执行路径是有差异的,因此观察运行栈一定可以发现点什么。
但问题是对于代码里的Servlet类,可以使用eclipse的调试手段,在代码里打上断点,观察执行栈,但对于jsp来说,使用打断点来检查栈的方法就行不通了。那怎么办呢?
其实方法很简单,jsp页面内可以写Java代码,因此可以在页面上定义一个java.lang.Throwable
对象,然后使用该对象来输出当前调用栈。代码样例如下所示:
于是调整action后缀的配置,使用浏览器访问页面,提取页面生成的栈。
如下是action后缀配置为jsp,action
时的栈。
java.lang.Throwable
at org.apache.jsp.index_jsp._jspService(index_jsp.java:115)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:438)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:385)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:329)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:232)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.java:64)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:702)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:450)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:375)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:302)
at org.apache.struts2.dispatcher.ServletDispatcherResult.doExecute(ServletDispatcherResult.java:164)
at org.apache.struts2.dispatcher.StrutsResultSupport.execute(StrutsResultSupport.java:191)
at com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:372)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:276)
at org.apache.struts2.interceptor.DeprecationInterceptor.intercept(DeprecationInterceptor.java:41)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:229)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:229)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:73)
at com.opensymphony.服务器托管网xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at org.apache.struts2.interceptor.DateTextFieldInterceptor.intercept(DateTextFieldInterceptor.java:125)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:91)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:189)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54)
at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:567)
at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:81)
at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.java:71)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:105)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:506)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:1078)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:757)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1520)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
如下是action后缀配置为action
时的栈。
java.lang.Throwable
at org.apache.jsp.index_jsp._jspService(index_jsp.java:115)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:438)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:385)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:329)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:232)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.catalina.filters.HttpHeaderSecurityFilter.doFilter(HttpHeaderSecurityFilter.java:120)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:96)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.java:71)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:105)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:506)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:1078)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:757)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1520)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
对比之下,有如下发现:
-
当action后续为
jsp,action
时- 栈信息很长。
- 栈中出现了很多Struts2相关的栈帧(stack frame),说明页面访问请求被Struts2的过滤器拦截,符合预期。
- 栈中未出现
HttpHeaderSecurityFilter
相关的栈帧(stack frame)。 -
Log4jServletFilter
相关的栈帧(stack frame)出现了两次,为什么?
-
当前action后缀为
action
时- 栈信息很短。
- 栈中没有Struts2相关的栈帧(stack frame),说明页面访问请求没有被被Struts2的过滤器拦截,符合预期。
- 栈中出现了
HttpHeaderSecurityFilter
相关的栈帧(stack frame)。 -
Log4jServletFilter
相关的栈帧(stack frame)出现了一次,有点意思。
旧的问题没解决,新的问题又出现了。action后缀的配置,看来不单对HttpHeaderSecurityFilter
产生了影响,对Log4jServletFilter
的行为也有影响。
于是检查Log4jServletFilter
的配置,如下
org.springframework.web.util.Log4jConfigListener
org.apache.logging.log4j.web.Log4jServletContextListener
log4jServletFilter
org.apache.logging.log4j.web.Log4jServletFilter
log4jServletFilter
/*
REQUEST
FORWARD
INCLUDE
ERROR
咦,怎么filter-mapping
还可以配置dispatcher
,这是什么鬼?先不管它,参照Log4jServletFilter
的配置,修改HttpHeaderSecurityFilter
的配置信息。
httpHeaderSecurity
org.apache.catalina.filters.HttpHeaderSecurityFilter
true
httpHeaderSecurity
/*
REQUEST
FORWARD
重启应用之后使用浏览器的调试面板观察页面的响应数据,久违的HTTP安全头部终于出现了。
Content-Type:text/html;charset=UTF-8
Date:Tue, 24 May 2016 16:15:21 GMT
Server:Apache-Coyote/1.1
Strict-Transport-Security:max-age=0
Transfer-Encoding:chunked
X-Content-Type-Options:nosniff
X-Frame-Options:DENY
X-XSS-Protection:1; mode=block
这时,检查栈信息,可以看到HttpHeaderSecurityFilter
相关的栈帧(stack frame)。
java.lang.Throwable
at org.apache.jsp.index_jsp._jspService(index_jsp.java:115)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:438)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:385)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:329)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:232)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.catalina.filters.HttpHeaderSecurityFilter.doFilter(HttpHeaderSecurityFilter.java:120)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.java:64)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:702)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:450)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:375)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:302)
at org.apache.struts2.dispatcher.ServletDispatcherResult.doExecute(ServletDispatcherResult.java:164)
at org.apache.struts2.dispatcher.StrutsResultSupport.execute(StrutsResultSupport.java:191)
at com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:372)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:276)
at org.apache.struts2.interceptor.DeprecationInterceptor.intercept(DeprecationInterceptor.java:41)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:229)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.Defau服务器托管网ltActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:229)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:73)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at org.apache.struts2.interceptor.DateTextFieldInterceptor.intercept(DateTextFieldInterceptor.java:125)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:91)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:189)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54)
at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:567)
at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:81)
at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.java:71)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:105)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:506)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:1078)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:757)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1520)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
定位结论
折腾这么久,终于把解决方法整出来了,其实很简单。
当前struts.xml中有如下配置
配置安全头部的过滤器时,需要在URL匹配模式上增加REQUEST
和FORWARD
。
httpHeaderSecurity
org.apache.catalina.filters.HttpHeaderSecurityFilter
true
httpHeaderSecurity
/*
REQUEST
FORWARD
原因应该和Struts2重定向请求至页面的方式相关,不过暂时没有时间去研究Struts2,期望后续会有所了解。
资料
关于dispatcher
的一些资料。
- web.xml里中的作用
- Web.xml中Filter过滤器标签几个说明
- filter-mapping的执行顺序和字符集设置的优先级
- Filtering Requests and Responses
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
相关推荐: java中小微医疗机构云服务(云HIS)平台源码
云HIS(Cloud-Based Healthcare Information System)重新定义了HIS,目标是为中小型医疗卫生机构提供优质经济的医疗卫生信息化产品及服务;是以健康档案为主线、以电子病历为核心、以云计算技术为基础的医疗卫生系统。云HIS作…