HTTP安全头部对jsp页面不生效

这篇具有很好参考价值的文章主要介绍了HTTP安全头部对jsp页面不生效。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文于2016年4月底完成,发布在个人博客网站上。
考虑个人博客因某种原因无法修复,于是在博客园安家,之前发布的文章逐步搬迁过来。


诡异的问题

AppScan扫描报告中提示,Web服务器返回jscsspngjsp页面的HTTP响应中缺少安全头部。HTTP的安全头部包括HTTP Strict Transport SecurityX-Frame-OptionsX-Content-Type-OptionsX-XSS-ProtectionContent-Security-Policy

网上资料很多,于是参照资料修改$CATALINA_BASE/conf/web.xml,增加相关配置,如下是样例:

<filter>
    <filter-name>httpHeaderSecurity</filter-name>
    <filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-class>
    <async-supported>true</async-supported>
</filter>
<filter-mapping>
    <filter-name>httpHeaderSecurity</filter-name>
    <url-pattern>/*</url-pattern>  <!-- 注意:Jackie遇到的问题与httpHeaderSecurity的配置相关。 -->
</filter-mapping>

本以为这样修改之后问题就解决了,所以也没用浏览器的调试面板去仔细检查Web服务器响应数据的HTTP头部;但天不遂人愿,事情并没有如预想的方向发展。

在稍后的一份AppScan扫描报告中,居然又看到了Web服务器返回的HTTP响应缺少安全头部的提示。不过这次稍有区别,报告中只提示jsp页面的访问存在问题。于是使用浏览器的调试面板仔细查看Web服务器返回的响应信息,发现Web服务器返回jscsspng时,在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中的配置如下:

<filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

简化后的struts.xml配置文件,内容如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
    <constant name="struts.enable.DynamicMethodInvocation" value="false" />
    <constant name="struts.devMode" value="true" />
    <constant name="struts.action.extension" value="jsp,action"/> <!-- 注意这里 -->
    <constant name="struts.ui.theme" value="java"></constant>
    <constant name="struts.objectFactory" value="spring" />
    <constant name="struts.i18n.encoding" value="UTF-8" />
    <package name="default" namespace="/" extends="struts-default">

        <interceptors>
            <interceptor-stack name="myStack">  
                <interceptor-ref name="basicStack"></interceptor-ref>  
            </interceptor-stack> 
        </interceptors>  
  
        <default-interceptor-ref name="myStack" /> 
        
        <global-results>
            <result name="error">/error.jsp</result>
        </global-results>

        <global-exception-mappings>
            <exception-mapping exception="java.lang.Exception" result="error"/>
        </global-exception-mappings>

        <action name="*" class="MainAction">
            <result name="success">{1}.jsp</result>
        </action>
    </package>
</struts>

通用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文件中的配置,如下:

<filter>
    <filter-name>httpHeaderSecurity</filter-name>
    <filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-class>
    <async-supported>true</async-supported>
</filter>
<filter-mapping>
    <filter-name>httpHeaderSecurity</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

没看出来什么特别的地方,而官方文档对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后缀的配置

<constant name="struts.action.extension" value="action"/>

如下是B项目struts.xml文件中action后续的配置

<constant name="struts.action.extension" value="jsp,action"/>

问题在于A项目并没有遇到B项目现在遇到的问题。

分析到这里,尝试调整struts.xml的配置,去掉配置中的jsp,如下所示

<constant name="struts.action.extension" value="action"/>

这样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对象,然后使用该对象来输出当前调用栈。代码样例如下所示:

<%
	new Throwable().printStackTrace();
%>

于是调整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的配置,如下

<listener>   
   <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>  
</listener>   

 <!-- log4j2-begin -->
 <listener>
     <listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class>
 </listener>
 <filter>
     <filter-name>log4jServletFilter</filter-name>
     <filter-class>org.apache.logging.log4j.web.Log4jServletFilter</filter-class>
 </filter>
 <filter-mapping>
     <filter-name>log4jServletFilter</filter-name>
     <url-pattern>/*</url-pattern>
     <dispatcher>REQUEST</dispatcher>
     <dispatcher>FORWARD</dispatcher>
     <dispatcher>INCLUDE</dispatcher>
     <dispatcher>ERROR</dispatcher>
 </filter-mapping>  

咦,怎么filter-mapping还可以配置dispatcher,这是什么鬼?先不管它,参照Log4jServletFilter的配置,修改HttpHeaderSecurityFilter的配置信息。

<filter>
    <filter-name>httpHeaderSecurity</filter-name>
    <filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-class>
    <async-supported>true</async-supported>
</filter>
<filter-mapping>
    <filter-name>httpHeaderSecurity</filter-name>
    <url-pattern>/*</url-pattern>
	<dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

重启应用之后使用浏览器的调试面板观察页面的响应数据,久违的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.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)

定位结论

折腾这么久,终于把解决方法整出来了,其实很简单。

当前struts.xml中有如下配置

<constant name="struts.action.extension" value="action,jsp"/>

配置安全头部的过滤器时,需要在URL匹配模式上增加REQUESTFORWARD

<filter>
    <filter-name>httpHeaderSecurity</filter-name>
    <filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-class>
    <async-supported>true</async-supported>
</filter>
<filter-mapping>
    <filter-name>httpHeaderSecurity</filter-name>
    <url-pattern>/*</url-pattern>
	<dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

原因应该和Struts2重定向请求至页面的方式相关,不过暂时没有时间去研究Struts2,期望后续会有所了解。

资料

关于dispatcher的一些资料。文章来源地址https://www.toymoban.com/news/detail-779072.html

  • web.xml里中的作用
  • Web.xml中Filter过滤器标签几个说明
  • filter-mapping的执行顺序和字符集设置的优先级
  • Filtering Requests and Responses

到了这里,关于HTTP安全头部对jsp页面不生效的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 什么是HTTP头部(HTTP headers)?

    前端入门之旅:探索Web开发的奇妙世界 欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发者,这里都将为你提供一个系统而又亲切的学习平台。在这个

    2024年02月07日
    浏览(39)
  • http请求头部(header)详解

    通常HTTP消息包括客户机向服务器的请求消息和服务器向客户机的响应消息。这两种类型的消息由一个起始行,一个或者多个头域,一个只是头域结束的空行和可 选的消息体组成。HTTP的头域包括通用头,请求头,响应头和实体头四个部分。每个头域由一个域名,冒号(:)和域

    2024年02月12日
    浏览(42)
  • HTTP 头部- Origin Referer

    Origin Header 示例 Origin 请求头部是一个 HTTP 头部,它提供了发起请求的网页的源(协议、域名和端口)信息。它通常在进行跨域资源共享(CORS)请求时使用,以便服务器可以决定是否接受请求。 假设我们在浏览器的地址栏输入并访问 http://www.example.com ,这个网站上有一个 AJ

    2024年02月21日
    浏览(34)
  • HTTP头部信息解释(超级详细)

    本篇文章将会详细的介绍HTTP头部信息,若大家在使用过程中有不了解的,可以适当参考。 若有问题,欢迎随时私聊!!! HTTP头部信息是HTTP协议中的一部分,它包含了HTTP请求和响应的元数据信息。HTTP头部由一组由冒号分隔的键值对组成,每个键值对占一行,每行以回车换行

    2024年02月16日
    浏览(45)
  • SQL注入之HTTP头部注入

    向服务器传参三大基本方法:GPC GET方法,参数在URL中 POST,参数在body中 COOKIE,参数http在请求头部中COOKIE cookie注入的注入点在cookie数据中,以sqil-labs-20关为例,做cookie注入练习,在虚拟机中打开链接http://127.0.0.1/sqli-labs-master/Less-20/index.php,用户名和密码都输入dumb登录 打开火狐

    2024年02月11日
    浏览(42)
  • linux iptables规则修改完成后怎么立即生效

    在修改 iptables 规则后,可以使用以下命令立即生效: 使用 service iptables save 命令来保存规则,然后使用 service iptables restart 重启 iptables 服务。 使用 /etc/init.d/iptables restart 命令重启 iptables 服务。 注意:使用这些命令时需要 root 权限。 另外,如果想永久保存 iptables 规则,可以

    2024年02月12日
    浏览(47)
  • JavaWeb中Servlet+jsp+JDBC完成登录注册界面

    前言 一、登录注册思路 二、前端页面 1.Login 2.Register 3.UserList界面 三、后端代码 1.封装实体类User类 2.Login对应的Servlet(验证信息功能) 3.Register对应的Servlet(增加功能) 4.工具类(DbUtil) 5.properties文件格式及所在目录 6.用户列表(查询功能)  总结 例如:学习javaweb过程笔记

    2024年02月08日
    浏览(62)
  • HTTP头部信息解释分析(详细整理)(转载)

    这篇文章为大家介绍了HTTP头部信息,中英文对比分析,还是比较全面的,若大家在使用过程中遇到不了解的,可以适当参考下 HTTP 头部解释 1. Accept: 告诉WEB服务器自己接受什么介质类型, / 表示任何类型,type/* 表示该类型下的所有子类型,type/sub-type。 2. Accept-Charset: 浏览

    2024年02月05日
    浏览(41)
  • 【SQL注入漏洞-06】HTTP头部注入靶场实战

    常见的sql注入一般是 通过请求参数或者表单进行注入 ,HTTP头部注入是 通过HTTP协议头部字段值进行注入 。 产生HTTP头部注入的条件: 能够对请求头消息进行修改 修改的请求头信息能够带入数据库进行查询 数据库没有对输入的请求信息做过滤 User-Agent :是Http协议中的一部分

    2024年02月02日
    浏览(59)
  • 使用jsp、HttpServlet完成一个登录、注册,并用MySQL连接数据进行操作

    这两个是写数据库的软件。  启动MySQL对应的版本型号。 user表 1.判断存在(有没有login的数据库,有就删掉)即删除。 DROP DATABASE IF EXISTS login; 2.创建数据库,使用数据库  #创建数据库 CREATE DATABASE login; #使用数据库 use login; 3.创建一个表我们这定义叫user,给表增添3条数据 #创

    2024年02月04日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包