XSS过滤器Filter实现全过程

需求:
对用户输入的内容进行过滤,转义特殊字符,防止部分XSS攻击
项目基础:
前端采用form+ajax提交数据,后端采用SpringMVC框架,@RequestMapping注解的方法接收前端参数。其中还有用到multipart/form-data传输文件。
实现步骤:
一、实现XSSFilter类
二、实现XssHttpServletRequestWraper类
三、在web.xml注册过滤器

一、实现XssFilter

public class XssFilter implements Filter{
    
    
	//	为了解决multipart/form-data过滤器过滤之后controller接收不到数据的问题
	//如果没有用到,可以把相关内容删除去
	private MultipartResolver multipartResolver=null;

	@Override
	public void init(FilterConfig filterConfig) throws ServletException{
    
    
		//注入bean
		multipartResolver=(MultipartResolver)ApplicationContextUtils.getApplicationContext().getBean("multipartResolver",MultipartResolver.class);
	}
	
	@Override
	public void doFilter(ServletRequest request , ServletResponse response , FilterChain chain) 
			throws IOException , ServletException{
    
    
		String contentType=request.getContentType();
		if(contentType!=null && contentType.contains("multipart/form-data")){
    
    
			//form-data过滤
			MultipartHttpServletRequest multipartRequest=multipartResolver.resolveMultipart((HttpServletRequest) request);
			XssHttpServletRequestWraper xssRequest=new XssHttpServletRequestWraper(multipartRequest);
			chain.doFilter(xssRequest, response);
		}else{
    
    
			//普通过滤
			XssHttpServletRequestWraper xssRequest=new XssHttpServletRequestWraper((HttpServletRequest)request);
			chain.doFilter(xssRequest, response);
		}
	}
	
	@Override
	public void destroy(){
    
    
		
	}	
}

其中如果要对multipart/form-data 过滤,除了上述过滤器的内容外,还要编写ApplicationContextUtils.class,并在spring配置文件注册bean

ApplicationContextUtils.class内容为:

//对Spring容器进行各种上下文操作的工具类
public class ApplicationContextUtils implements ApplicationContextAware{
    
    
	
	private static ApplicationContext context;

	@Override
	public void setApplicationContext(ApplicationContext context) throws BeansException {
    
    
		ApplicationContextUtils.context = context;
	}
	
	public static ApplicationContext getApplicationContext(){
    
    
		return context;
	}
	//根据Bean名称获取Bean对象
	public static Object getBean(String beanName){
    
    
		return context.getBean(beanName);
	}
	
	public static Object getMassage(String key){
    
    
		return context.getMessage(key, null,Locale.getDefault());
	}
}

在ApplicationContext.xml注册内容为:

	<!-- =========================注册文件上传 -->
	<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<!-- 文件上传大小限制 -->
		<property name="maxUploadSize">
			<value>104857600</value>
		</property>
		<property name="defaultEncoding">
			<value>UTF-8</value>
		</property>
	</bean>
	
	<bean id="applicationContextUtils" class="ApplicationContextUtils在项目存放的位置" lazy-init="false" />

二、实现XssHttpServletRequestWraper类

public class XssHttpServletRequestWraper extends HttpServletRequestWrapper{
    
    
	
	public XssHttpServletRequestWraper(HttpServletRequest servletRequest){
    
    
		super(servletRequest);
	}
	
	@Override
	public String getHeader(String name){
    
    
		return super.getHeader(name);
	}
	
	@Override
	public String getParameter(String name){
    
    
		String value = super.getParameter(name);
		return xssEncode(value);
	}
	
	//对以FormData形式提交,Content-Type:application/x-www-from-urlencoded参数过滤
	@Override
	public String[] getParameterValues(String name){
    
    
		String[] values=super.getParameterValues(name);
		if(values==null){
    
    
			return null;
		}
		int count=values.length;
		String[] encodeValues=new String[count];
		for(int i=0;i<count;i++){
    
    
			encodeValues[i]=xssEncode(values[i]);
		}
		return encodeValues;
	}
	
	/*过滤策略:把特殊字符转为HTML实体编码,
	*这样存在数据库里较安全
	*返回给前端时会被js解析为正常字符,不影响查看*/
	public static String xssEncode(String str){
    
    
		if(str == null || str.isEmpty()){
    
    
			return str;
		}
		str = str.replaceAll(";", "&#59;");
		str = str.replaceAll("<", "&#60;").replaceAll(">", "&#62;");
		str = str.replaceAll("\\(", "&#40;").replaceAll("\\)", "&#41;");
		str = str.replaceAll("'", "&#39;").replaceAll("\"", "&#34;");
		str = str.replaceAll("\\$", "&#36;");
		str = str.replaceAll("%", "&#37;");
		str = str.replaceAll("\\/", "&#47;").replaceAll("\\\\", "&#92;");
		str = str.replaceAll(":", "&#58;");
		str = str.replaceAll("\\?", "&#63;").replaceAll("@", "&#64;");
		str = str.replaceAll("\\^", "&#94;");
		return str;
	}
}

三、在web.xml注册过滤器:
最好放在字符过滤器之后

<filter>
	<filter-name>XssFilter</filter-name>
	<filter-class>XssFilter在项目存放的位置</filter-class>
</filter>
<filter-mapping>
	<filter-name>XssFilter</filter-name>
	<url-partten>/*<url-partten>
	<dispatcher>REQUEST</dispatcher>
</filter-mapping>

自此,过滤器的实现和配置就完成了。前端输入
<script>alert("1");</script>
后,后台会解析为&#60;script&#62;alert&#40;&#34;1&#34;&#41;&#59;&#60;&#47;script&#62;
并存入数据库,而在前端显示时又会显示为原来的字符,且不会执行js语句。

楼主在返回给前端时发现,如果是html(str)显示,则能显示原来字符。如果是val(str)返回给文本框的话,则并不会把HTML实体字符解析为正常字符。所以需要我们写个解析函数。具体的也很简单,在此就不贴代码了。

猜你喜欢

转载自blog.csdn.net/qq_38118138/article/details/118081903