注:本文非本人原著。
demo的地址:链接:http://pan.baidu.com/s/1miEmHMo 密码:k5ca
如何过滤Xss跨站脚本攻击,我想,Xss跨站脚本攻击令人为之头疼。为什么呢。
尤其是有富文本编辑器的产品。xss可能出现在http的head,不说别的,新浪多次出现。
xss可以出现在post数据的正文。图片的url。
于是各种Xss横行,如今Xss跨站脚本漏洞的流行程度甚至超过了当年的sql。
那么对于JAVA语言,如何防御呢。
笔者分享一个思路:所有的web项目,所有的参数都是request获得。
不管是json合适xml又或者post表单数据。甚至图片、文件等等都是如此。
那么,如果对request做个手脚。是不是就可以过滤xss了呢。
正是如此。
如下分享代码。网络上也有类似的过滤器,但不如笔者这份强悍。
package com.blog.web.base.wrapper; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern; import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper; /**
* 覆写Request方法,过滤XSS恶意脚本
*
* @author WebSOS
* @time 2015-06-09
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { HttpServletRequest orgRequest = null; public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
orgRequest = request;
} /**
* 覆盖getParameter方法,将参数名和参数值都做xss过滤。
*/
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
if (value != null) {
value = xssEncode(value);
}
return value;
} /**
* 覆盖getHeader方法,将参数名和参数值都做xss过滤。 避免部分head操作引发的xss
*/
@Override
public String getHeader(String name) { String value = super.getHeader(name);
if (value != null) {
value = xssEncode(value);
}
return value;
} /**
* 覆盖getHeaderNames方法,避免穷举head参数名引发的xss
*/
@Override
public Enumeration<String> getHeaderNames() { Enumeration<String> headNames = super.getHeaderNames();
String value = null;
List<String> values = new ArrayList<String>();
while (headNames.hasMoreElements()) {
try {
value = (String) headNames.nextElement();
if (value == null) {
continue;
}
value = xssEncode(value);
values.add(value);
} catch (Exception e) {
e.printStackTrace();
}
}
if (values.isEmpty()) {
return null;
}
headNames = new XssEnumerator(0, values.size(), values);
return headNames;
} /**
* 覆盖getParameterNames方法,避免穷举参数名引发的xss
*/
@Override
public Enumeration<String> getParameterNames() {
Enumeration<String> paraNames = super.getParameterNames();
if (paraNames == null) {
return null;
}
String value = null;
List<String> values = new ArrayList<String>();
while (paraNames.hasMoreElements()) {
try {
value = (String) paraNames.nextElement();
if (value == null) {
continue;
}
value = xssEncode(value);
values.add(value);
} catch (Exception e) {
e.printStackTrace();
}
}
if (values.isEmpty()) {
return null;
}
paraNames = new XssEnumerator(0, values.size(), values);
return paraNames;
} /**
* 覆盖getParameterMap方法,避免穷举参数名或值引发的xss
*/
@Override
public Map<String, String[]> getParameterMap() {
Map<String, String[]> map = super.getParameterMap();
Map<String, String[]> paraMap = new HashMap<String, String[]>();
if (map == null) {
return null;
}
String[] values = null;
for (String key : map.keySet()) {
try {
values = map.get(key);
if (values != null) {
for (int i = 0; i < values.length; i++) {
try {
values[i] = xssEncode(values[i]);
} catch (Exception e) {
e.printStackTrace();
}
}
}
paraMap.put(xssEncode(key), values);
} catch (Exception e) {
e.printStackTrace();
}
}
return paraMap;
} /**
* 覆盖getInputStream方法,避免上传文件出现的xss或脚本代码
*/
@Override
public ServletInputStream getInputStream() throws IOException {
XSSServletInputStream xssServletInputStream = new XSSServletInputStream();
ServletInputStream inputStream = orgRequest.getInputStream(); ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
try {
int ch;
while ((ch = inputStream.read()) != -1) {
byteStream.write(ch);
}
} finally {
inputStream.close();
}
xssServletInputStream.stream = new ByteArrayInputStream(xssEncode(
new String(byteStream.toByteArray(), "iso-8859-1")).getBytes(
"iso-8859-1"));
return xssServletInputStream;
} /**
* 将容易引起xss漏洞的字符清理掉
*
* @param s
* @return
*/
private static String xssEncode(String value) {
if (value != null) {
/*
* value = value.replace("<", "<"); value = value.replace(">",
* ">");
*/
// 如需开启富文本请撤销以下注释 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("<img.*?on.*?=.*?>",
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("eval\\((.*?)\\)",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll(""); scriptPattern = Pattern.compile("expression\\((.*?)\\)",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll(""); scriptPattern = Pattern.compile("expression\\((.*?)\\)",
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("vbscript:",
Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll(""); scriptPattern = Pattern.compile("onload(.*?)=",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll(""); scriptPattern = Pattern.compile("<%.*?java.*?%>", Pattern.CASE_INSENSITIVE
| Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll(""); scriptPattern = Pattern.compile("<jsp:.*?>.*?</jsp:.*?>",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll(""); scriptPattern = Pattern.compile("<meta.*?>",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll(""); }
return value;
} /**
* 获取最原始的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;
} private class XSSServletInputStream extends ServletInputStream {
private InputStream stream; @Override
public int read() throws IOException {
return stream.read();
}
} private class XssEnumerator implements Enumeration<String> {
int count; // 计数器
int length; // 存储的数组的长度
List<String> dataArray; // 存储数据数组的引用 XssEnumerator(int count, int length, List<String> dataArray) {
this.count = count;
this.length = length;
this.dataArray = dataArray; } public boolean hasMoreElements() {
return (count < length);
} public String nextElement() {
return dataArray.get(count++);
}
} public static void main(String[] args) {
Enumeration<String> paraNames = (Enumeration<String>) new ArrayList();
}
}