之前的开发中只是做业务开发,也就不会管这些,现在有机会去考虑做这些事了,也看到项目中有对xss攻击的防范措施,来学习一下:
整个流程:
1、对请求参数进行处理,如果有半角符则把半角符替换为全角符。
2、对请求参数值进行处理,如果请求参数值有半角符则吧半角符替换为全角符。
实现方式:
1、在拦截器中进行拦截处理
2、实现方式是通过重写HttpServletRequestWrapper的方法来实现
下面来看代码:
一、Filter的实现
package com.jeecms.common.web;
import com.jeecms.core.utils.PropertiesMoreUtils;
import com.jeecms.core.web.util.URLHelper;
import org.apache.commons.lang.StringUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class XssFilter implements Filter {
private String filterChar;
private String replaceChar;
private String splitChar;
private String excludeUrls;
private Map<String, String[]> sysNo_xssExcludeUrlsFromProperties_map = new HashMap<String, String[]>();
FilterConfig filterConfig = null;
public void init(FilterConfig filterConfig) throws ServletException {
this.filterChar = filterConfig.getInitParameter("FilterChar");
this.replaceChar = filterConfig.getInitParameter("ReplaceChar");
this.splitChar = filterConfig.getInitParameter("SplitChar");
this.excludeUrls = filterConfig.getInitParameter("excludeUrls");
this.filterConfig = filterConfig;
}
public void destroy() {
this.filterConfig = null;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
/**如果都时特殊路径则不进行过滤*/
if (isExcludeUrl(request) || isExcludeUrlFromProperties(request)) {
chain.doFilter(request, response);
} else {
/**对请求参数和参数值进行处理,我们看到这里request对象传的是XssHttpServletRequestWrapper是一个自定义类,具体的见代码*/
/**这样之后我们调用获取参数的方法都是调用XssHttpServletRequestWrapper的方法*/
chain.doFilter(new XssHttpServletRequestWrapper((HttpServletRequest) request, filterChar, replaceChar, splitChar), response);
}
}
/**
* 配置文件中配置不用拦截处理的特殊路径
* @param request
* @return
*/
private boolean isExcludeUrlFromProperties(ServletRequest request) {
String sysNo = PropertiesMoreUtils.getInstance().get("pf", "sys_no");
if (StringUtils.isEmpty(sysNo))
return false;
boolean exclude = false;
String[] xssExcludeUrlsFromPropertiesAry = null;
if (PropertiesMoreUtils.getInstance().isPropertiesChanged(sysNo) || sysNo_xssExcludeUrlsFromProperties_map.get(sysNo) == null) {
String xssExcludeUrls = PropertiesMoreUtils.getInstance().get(sysNo, "xssExcludeUrls", "");
xssExcludeUrlsFromPropertiesAry = xssExcludeUrls.split(",");
sysNo_xssExcludeUrlsFromProperties_map.put(sysNo, xssExcludeUrlsFromPropertiesAry);
} else {
xssExcludeUrlsFromPropertiesAry = sysNo_xssExcludeUrlsFromProperties_map.get(sysNo);
}
if (xssExcludeUrlsFromPropertiesAry != null && xssExcludeUrlsFromPropertiesAry.length > 0) {
for (String url : xssExcludeUrlsFromPropertiesAry) {
if (StringUtils.isEmpty(url))
continue;
if (URLHelper.getURI((HttpServletRequest) request).startsWith(url)){
exclude = true;
break;
}
}
}
return exclude;
}
/**
* filterConfig中配置的可执行路径
* @param request
* @return
*/
private boolean isExcludeUrl(ServletRequest request) {
boolean exclude = false;
if (StringUtils.isNotBlank(excludeUrls)) {
String[] excludeUrl = excludeUrls.split(splitChar);
if (excludeUrl != null && excludeUrl.length > 0) {
for (String url : excludeUrl) {
if (URLHelper.getURI((HttpServletRequest) request).startsWith(url)) {
exclude = true;
break;
}
}
}
}
return exclude;
}
}
二、Filter的配置文件
<!--@分隔 -->
<filter>
<filter-name>XssFilter</filter-name>
<filter-class>com.jeecms.common.web.XssFilter</filter-class>
<init-param>
<param-name>excludeUrls</param-name>
<param-value>/member/contribute@/jeeadmin/jeecms@/flow_statistic</param-value>
</init-param>
<init-param>
<param-name>SplitChar</param-name>
<param-value>@</param-value>
</init-param>
<init-param>
<param-name>FilterChar</param-name>
<param-value>'@"@\@#@%@></param-value>
</init-param>
<init-param>
<param-name>ReplaceChar</param-name>
<param-value>‘@“@\@#@%@></param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>XssFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
三、自定义类HttpServletRequestWrapper
在Filter中我们传了一个XssHttpServletRequestWrapper类对象,XssHttpServletRequestWrapper这个类继承了HttpServletRequestWrapper 而HttpServletRequestWrapper实现了HttpServletRequest 接口所以HttpServletRequestWrapper 中实现了所有HttpServletRequest 接口中的方法,当XssHttpServletRequestWrapper继承HttpServletRequestWrapper 后重写了要用到的方法来满足我们过滤特殊字符的需求,所以在控制层调用的方法其实都是XssHttpServletRequestWrapper对象的方法,而这个对象的部分方法我们是进行了重写来实现xss攻击的处理,具体处理方法见下面代码中重写的方法!
package com.jeecms.common.web;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import static com.jeecms.common.web.Constants.UTF8;
/**
* @author Tom
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
private String[]filterChars;
private String[]replaceChars;
public XssHttpServletRequestWrapper(HttpServletRequest request,String filterChar,String replaceChar,String splitChar) {
//调用父类的构造函数创建对象
super(request);
if(filterChar!=null&&filterChar.length()>0){
filterChars=filterChar.split(splitChar);
}
if(replaceChar!=null&&replaceChar.length()>0){
replaceChars=replaceChar.split(splitChar);
}
}
public String getQueryString() {
String value = super.getQueryString();
if (value != null) {
value = xssEncode(value);
}
return value;
}
/**
* 覆盖getParameter方法,将参数名和参数值都做xss过滤。<br/>
* 如果需要获得原始的值,则通过super.getParameterValues(name)来获取<br/>
* getParameterNames,getParameterValues和getParameterMap也可能需要覆盖
*/
public String getParameter(String name) {
//调用父类的方法来获取请求参数,继承HttpServletRequestWrapper的目的就是使用这些现成的方法!
String value = super.getParameter(xssEncode(name));
if (value != null) {
value = xssEncode(value);
}
return value;
}
public String[] getParameterValues(String name) {
String[]parameters=super.getParameterValues(name);
if (parameters==null||parameters.length == 0) {
return null;
}
for (int i = 0; i < parameters.length; i++) {
parameters[i] = xssEncode(parameters[i]);
}
return parameters;
}
/**
* 覆盖getHeader方法,将参数名和参数值都做xss过滤。<br/>
* 如果需要获得原始的值,则通过super.getHeaders(name)来获取<br/> getHeaderNames 也可能需要覆盖
*/
public String getHeader(String name) {
String value = super.getHeader(xssEncode(name));
if (value != null && !name.equals("Referer")) {
value = xssEncode(value);
}
return value;
}
/**
* 将容易引起xss漏洞的半角字符直接替换成全角字符
*
* @param s
* @return
*/
private String xssEncode(String s) {
if (s == null || s.equals("")) {
return s;
}
try {
s = URLDecoder.decode(s, UTF8);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//容易引起xss漏洞的半角字符直接替换成全角字符
for (int i = 0; i < filterChars.length; i++) {
if(s.contains(filterChars[i])){
s=s.replace(filterChars[i], replaceChars[i]);
}
}
return s;
}
}
总结:
这样我们就实现了对xss攻击的处理,其实就是对所有请求使用Filter进行拦截在将请求参数和请求参数值进行了处理,而处理的方式就是重写HttpServletRequest接口的方法进行处理。重写HttpServletRequest接口方法有两种一种就是实现这个接口这样的话我们就要去实现一个个的方法而另一种方法就是继承HttpServletRequestWrapper这个类,因为他已经实现了HttpServletRequest接口的方法,我们不用一个个去实现,如果需要的话就可以直接调用!