使用filter解决xss攻击的实现思路,其实是通过正则的方式对请求的参数做脚本的过滤,但是这需要对所要过滤的脚本做很多的枚举。下面这个demo是我在工作中用到的,希望对大家有所帮助。
主要实现方法是重写HttpServletRequestWrapper中的getParameter,getParameterMap,以及getParameterValues等方法处理请求的参数值
其中xssEncode()方法我只是对传入的< >进行了圆角<>替换,有简单js防止脚本注入,但是这远远不够,所以在stripXss()方法中枚举了很多存在脚本注入的正则表达式,对文本进行过滤处理。重写这个类之后,你需要定义一个XSSFilter,filter中调用该重写的HttpServletRequestWrapper。具体看代码
public class XSSFilter implements Filter {
public void destroy() {
// TODO Auto-generated method stub
}
/**
* 通过url只能访问action
*/
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
ServletException {
HttpServletRequest request = (HttpServletRequest) req;
request.setCharacterEncoding("utf-8");
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(request);
chain.doFilter(xssRequest, res);
}
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
HttpServletRequest orgRequest = null;
public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
orgRequest = request;
}
/**
* 覆盖getParameter方法,将参数名和参数值都做xss过滤。<br/>
* 如果需要获得原始的值,则通过super.getParameterValues(name)来获取<br/>
* getParameterNames,getParameterValues和getParameterMap也可能需要覆盖
*/
@Override
public String getParameter(String name) {
String value = super.getParameter(xssEncode(name));
if (value != null) {
value = xssEncode(value);
}
return value;
}
@Override
public Map<String, String[]> getParameterMap() {
Map<String, String[]> map = super.getParameterMap();
if (map != null) {
for (Map.Entry<String, String[]> entry : map.entrySet()) {
String[] values = entry.getValue();
List<String> newValues = new LinkedList<String>();
if (values != null) {
for (String s : values) {
String afertEncode = xssEncode(s);
newValues.add(afertEncode);
}
entry.setValue(newValues.toArray(new String[newValues.size()]));
}
}
}
return map;
}
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
return xssEncode(values);
}
protected String[] xssEncode(String[] values) {
if (values != null && values.length > 0) {
int length = values.length;
String[] escapseValues = new String[length];
for (int i = 0; i < length; i++) {
escapseValues[i] = xssEncode(values[i]);
}
return escapseValues;
}
return values;
}
/**
* 覆盖getHeader方法,将参数名和参数值都做xss过滤。<br/>
* 如果需要获得原始的值,则通过super.getHeaders(name)来获取<br/>
* getHeaderNames 也可能需要覆盖
*/
@Override
public String getHeader(String name) {
String value = super.getHeader(xssEncode(name));
if (value != null) {
value = xssEncode(value);
}
return value;
}
/**
* 将容易引起xss漏洞的半角字符直接替换成全角字符
*
* @param s
* @return
*/
private static String xssEncode(String s) {
if (s == null || "".equals(s)) {
return s;
}
StringBuilder sb = new StringBuilder(s.length() + 16);
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
switch (c) {
case '>':
sb.append('>');// 全角大于号
break;
case '<':
sb.append('<');// 全角小于号
break;
default:
sb.append(c);
break;
}
}
String value = stripXss(sb.toString());
return value;
}
/**
*过滤script脚本
* @param value
* @return
*/
private static String stripXss(String value){
if(StringUtils.isNotEmpty(value)){
Pattern scriptPattern =Pattern.compile("<script>(.*?)</script>",
Pattern.CASE_INSENSITIVE);
value=scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("</script>",
Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("<script(.*?)>",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("javascript:",
Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("<iframe>(.*?)</iframe>",
Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("</iframe>",
Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("<iframe(.*?)>",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("onload(.*?)=",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("oninput(.*?)=",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("onerror(.*?)=",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("onclick(.*?)=",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("confirm(.*?)",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("onfocus(.*?)=",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("alert(.*?)",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
}
return value;
}
// public static void main(String[] args) {
// System.out.println(stripXss("alert(gergerrg)"));
// }
/**
* 获取最原始的request
*
* @return
*/
public HttpServletRequest getOrgRequest() {
return orgRequest;
}
/**
* 获取最原始的request的静态方法
*
* @return
*/
public static HttpServletRequest getOrgRequest(HttpServletRequest req) {
if (req instanceof XssHttpServletRequestWrapper) {
return ((XssHttpServletRequestWrapper) req).getOrgRequest();
}
return req;
}
}