一、什么是Filter
Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。
Filter是Servlet2.3新增的一个特性,同时它也是Servlet技术中最使用的技术,开发人员通过Filter技术,能够实现对所有web资源的管理,如实现权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
简单来说,Filter实际上就是对web资源进行拦截,然后做一些处理,再交给下一个Filter或Servlet进行处理,通常情况下,Filter是用来拦截request进行处理的,当然,也可以对返回的response进行拦截处理。
Filter的应用场景比较多,如:编码格式设置、访问权限控制、敏感字符过滤、安全验证等
二、Filter的配置
2.1、基于web.xml
下面是Filter的一个基本形式
<web-app>
<filter>
<filter-name>Filter</filter-name>
<filter-class>myPackage.FilterClass</Filter-class>
</filter>
<filter-mapping>...</filter-mapping>
<web-app>
2.2、基于web.xml-filter元素
- icon 可选元素,声明IDE能够使用一个图像文件
- filter-name 必需元素,表示过滤器分配一个选定的名字
- display-name 可选元素,表示IDE使用的短名称
- description 可选元素,表示IDE的信息
- filter-class 必需元素,指定过滤器实现类的完全限定名
- init-param 可选元素,定义可利用FilterConfig的getInitParameter方法读取的初始化参数。单个过滤器元素可包含多个init-param元素。
2.3、基于web.xml-filter-mapping元素
- filter-name 必须与用filter元素声明时给予过滤器的名称相匹配
- url-pattern 此元素声明一个以斜杠(/)开头,用于设置filter所拦截的请求路径(过滤器关联的URL样式)
- servlet-name 用于指定过滤器所拦截的Servlet名称
Filter的配置-基于注解方式的其他标签
三、多个Filter的执行顺序
在我们的请求到达Servlet之间是可以经过多个Filter的,一般来说,建议Filter之间不要有关联,各自处理各自的逻辑即可。这样,我们也无需关心执行顺序问题。
如果一定要确保执行顺序,就要对配置进行修改了,执行顺序如下
1、在web.xml中,filter执行顺序跟<filter-mapping>的顺序有关,先声明的先执行
2、使用注解配置的话,filter的执行顺序跟名称的字母顺序有关,例如A_Filter会比B_Filter先执行
3、如果既有在web.xml中声明的Filter,也有通过注解配置的Filter,那么会优先执行web.xml中配置的Filter
四、FilterConfig详解(获取web.xml中的filter参数)
开发者在配置filter时,可以使用<init-param>为filter配置一些初始化参数,当web容器实例化Filter对象,调用其init方法时,会把封装了filter初始化参数的filterConfig对象传递进来。因此FilterConfig可以获取部署描述文件(web.xml)中分配的过滤器初始化参数.
FilterConfig有四个主要的方法如下:
- String getFilterName() //得到filter的名称
- String getInitParameter(String name) //返回在部署描述中指定名称的初始化参数的值。如果不存在返回null
- Enumeration getInitParameterNames() //返回过滤器的所有初始化参数的名字的枚举集合
- public ServletContext getServletContext() //返回Servlet上下文对象的引用
五、Filter的访问流程
当用户向服务器发送request请求时,服务器接收该请求,并将请求发送到第一个过滤器中进行处理,如果有多个过滤器,则会依次经过filter1=2、filter3 ... filter n,最终调用servlet中的service()方法,调用完毕后,按照与进入时相反的顺序,从过滤器filter n 开始,依次经过,直到过滤器filter 1,最终将处理后的结果返回给服务器,服务器再反馈给用户。
六、Filter的接口方法
在创建filter文件时,开发工具会提示开发者是否创建相应的接口方法,与servlet接口不同的是,filter接口在创建时就默认创建了所有的方法
6.1、Filter的接口方法-init()接口
与servlet中的init()方法类似,filter中的init()方法用于初始化过滤器,开发者可以在init()方法中完成与构造方法类似的初始化功能,如果初始化代码要用到FillerConfig对象,则这些初始化代码只能在Filler的init()方法中编写,而不能在构造方法中编写
6.2、Filter的接口方法-doFilter()接口
doFilter方法类似于Servlet接口中的service()方法。当客户端请求目标资源时,容器会筛选出符合<filter-mapping>标签的<url-pattern>的filter,并按照声明<filter-mapping>的顺序依次调用这些filter的doFilter()方法。
需要注意的时doFilter()方法有多个参数,其中参数request和response为web服务器或Filter链中的上一个Filter传递过来的请求和响应对象,参数chain代表当前Filter链的对象,只有当前Filter对象中的doFilter()方法内部需要调用FilterChain对象的doFilter()方法时,才能把请求交付给Filter链中的下一个Filter或者目标程序处理
6.3、Filter的接口方法-destory()接口
Filter中的destory()方法与servlet中的destory()作用类似,在web服务器卸载Filter对象之前被调用,用于释放被Filter对象打开的资源,如关闭数据库、关闭I/O流等
七、Filter的生命周期
Filter的生命周期与Servlet的生命周期比较类似,指的是Filter从创建直到销毁的整个过程,在一个生命周期中,Filter经历了被加载、初始化、提供服务及销毁的过程
当web容器启动时,会根据web.xml中声明的filter顺序依次实例化这些filter,然后在web应用程序加载调用init()方法,随机在客户端有请求时调用doFilter()方法,并且根据实际情况的不同,doFilter()方法可能被调用多次,最后在web应用程序卸载(或关闭)时调用destory()方法。
八、总结
- Filter是用于拦截请求的
- Filter的执行顺序要清楚
- Filter的拦截范围要清楚
- Filter的配置要牢记
九、Filter和Servlet总结
- Filter和Servlet都需要在web.xml或注解(@WebFilter、@WebServlet)中配置,而且配置方式是非常相似的;
- Filter和Servlet都可以处理来自Http请求的请求,两者都要request、reponse对象;
- 对于基于Filter和Servlet实现的简单架构项目,代码审计的重心集中于找出所有的Filter分析其过滤规则,找出是否有做全局的安全过滤、敏感的URL地址是否有做权限校验并尝试绕过Filter过滤
- 找出所有的Servlet,分析Servlet的业务是否存在安全问题,如果存在安全问题是否可以利用?是否有权限访问?利用是是否被Filter过滤等问题,切勿看到Servlet、JSP中的漏洞九妄下定论,不要忘了Servlet前面很有可能存在一个全局安全拦截过滤;
- Filter和Servlet基础概念不一样,Servlet定义是容器端小程序,用于直接处理后端业务逻辑,二Filter的思想则是实现对Java Web请求资源的拦截过滤;
- Filter和Servlet虽然概念上不太一样,但都可以处理Http请求,都可以用来实现MVC控制器(Struts2和Spring框架分别基于Filter和Servlet技术实现的);
- 一般来说Filter通常配置在MVC、Servlet和JSP请求前面,常用于后端权限控制、统一的Http请求参数过滤(统一的XSS、SQL注入、Struts2命令执行等攻击检测处理)处理,其核心主要体现在请求的过滤上,而Servlet更多的是用来处理后端业务请求上。