8.1 HttpFirewall 简介
在 Servlet 容器规范中,为 HttpServletRequest 定义了一些属性,如 contextPath、servletPath、pathInfo、queryString 等,这些属性都可以通过 get 方法获取。
然而,在 Servlet 容器规范中并没有定义这些属性可以包含哪些值,例如在 servletPath 和 pathInfo 中都可以包含 RFC2396 规范(https://www.ietf.org/rfc/rfc2396.txt)中定义的参数,不同容器对此处理方案也不同,有的容器会对此进行预处理,有的容器则不会。这种比较混乱的处理方式有可能会造成安全隐患,因此 Spring Security 中通过 HttpFirewall 来检查请求路径以及参数是否合法,如果合法,才会进入到过滤器链中进行处理。
HttpFirewall 是一个接口,它只有两个方法:
public interface HttpFirewall { FirewalledRequest getFirewalledRequest(HttpServletRequest request) throws RequestRejectedException; HttpServletResponse getFirewalledResponse(HttpServletResponse response); }
getFirewalledRequest 方法用来对请求对象进行检验并封装,getFirewalledResponse 方法则对响应对象进行封装。
FirewalledRequest 是封装后的请求类,但实际上该类只是在 HttpServletRequestWrapper 的基础上增加了 reset 方法。当 Spring Security 过滤器链执行完毕时,由 FilterChainProxy 负责调用该 reset 方法,以便重置全部或者部分属性。
FirewalledResponse 是封装后的响应类,该类主要重写了 sendRedirect、setHeader、addHeader 以及 addCookie 四个方法,在每一个方法中都对其参数进行校验,以确保参数中不含有\r 和\n。
HttpFirewall 一共有两个实现类,如图 8-1 所示。
图 8-1 HttpFirewall 的两个实现类
- DefaultHttpFirewall:虽然名字中包含 Default,但这并不是框架默认使用的 Http 防火墙,它只是一个检查相对宽松的防火墙。
- StrictHttpFirewall:这是一个检查严格的 Http 防火墙,也是框架默认使用的 Http 防火墙。
HttpFirewall 中对请求的合法性校验在 FilterChainProxy#doFilterInternal 方法中触发,具体可以参考 4.1.4 小节,这里不再赘述。
需要注意的是 HttpFirewall 的配置位置,在 Spring Security 框架中有两个地方涉及了 HttpFirewall 实例的获取:
(1)在 FilterChainProxy 属性定义中,默认创建的 HttpFirewall 实例就是 StrictHttpFirewall。
(2)FilterChainProxy 是在 WebSecurity#performBuild 方法中构建的,而 WebSecurity 实现了 ApplicationContextAware 接口,并实现了接口中的 setApplicationContext 方法,在该方法中,从 Spring 容器中查找到 HttpFirewall 对象并赋值给 httpFirewall 属性。最终在 performBuild 方法中,将 FilterChainProxy 对象构建成功后,如果 httpFirewall 不为 null,就把 httpFirewall 配置给 FilterChainProxy 对象。
根据以上两点可以得出:如果 Spring 容器中存在 HttpFirewall 实例,则最终使用 Spring 容器提供的 HttpFirewall 实例;如果 Spring 容器中不存在 HttpFirewall 实例,则使用 FilterChainProxy 中默认定义的 StrictHttpFirewall。进而可知,如果开发者不想使用默认的 StrictHttpFirewall 实例,则只需要自己提供一个 HttpFirewall 并注册到 Spring 容器中即可。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论