第一:修复建议:
1、在输入的地方进行严格的验证,例如个人信息的长度,电子邮箱的正则表达式的匹配.也就是我们俗称的白名单.
2、把用户输入任何位置的信息进行HTML编码,将用户输入所有<>和””进行替换.在应用程序中限制用户使用HTML标签跟熟悉.
3、去掉<script><a><img>
等标签
4、限制输入字符
5、去掉输入中的引号
6、对输入的URL进行解码,之后进行编码
第二:编写HttpServletRequest过滤规则
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
public class XSSRequestWrapper extends HttpServletRequestWrapper {
private static String key = "and|exec|insert|select|delete|update|count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+";
private static Set<String> notAllowedKeyWords = new HashSet<String>(0);
private static String replacedString = "非法字符";
final static int BUFFER_SIZE = 4096;
private final String[] xssKeyWord = {"javascript", "script", "onclick", "onload", "vbscript", "html", "expression"};
static {
String keyStr[] = key.split("\\|");
for (String str : keyStr) {
notAllowedKeyWords.add(str);
}
}
private String currentUrl;
private byte[] body; //用于保存读取body中数据
/**
* Constructs a request object wrapping the given request.
*
* @param request The request to wrap
* @throws IllegalArgumentException if the request is null
*/
public XSSRequestWrapper(HttpServletRequest request) {
super(request);
}
/**
* 覆盖getParameter方法,将参数名和参数值都做xss过滤。
* 如果需要获得原始的值,则通过super.getParameterValues(name)来获取
* getParameterNames,getParameterValues和getParameterMap也可能需要覆盖
*/
@Override
public String getParameter(String parameter) {
String value = super.getParameter(parameter);
if (value == null) {
return null;
}
return cleanXSS(value);
}
@Override
public String[] getParameterValues(String parameter) {
String[] values = super.getParameterValues(parameter);
if (values == null) {
return null;
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = cleanXSS(values[i]);
}
return encodedValues;
}
@Override
public Map<String, String[]> getParameterMap() {
Map<String, String[]> values = super.getParameterMap();
if (values == null) {
return null;
}
Map<String, String[]> result = new HashMap<>();
for (String key : values.keySet()) {
String encodedKey = cleanXSS(key);
int count = values.get(key).length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = cleanXSS(values.get(key)[i]);
}
result.put(encodedKey, encodedValues);
}
return result;
}
/**
* 覆盖getHeader方法,将参数名和参数值都做xss过滤。
* 如果需要获得原始的值,则通过super.getHeaders(name)来获取
* getHeaderNames 也可能需要覆盖
*/
@Override
public String getHeader(String name) {
String value = super.getHeader(name);
if (value == null) {
return null;
}
return cleanXSS(value);
}
private String cleanXSS(String valueP) {
boolean bool = false;
String value = valueP;
for (String s : xssKeyWord) {
if (valueP.contains(s)) {
bool = true;
break;
}
}
if (bool) {
//包含关键字 才过滤 < > ( ) '
value = value.replaceAll("<", "& lt;").replaceAll(">", "& gt;");
value = value.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41;");
value = value.replaceAll("'", "& #39;");
}
value = value.replaceAll("eval\\((.*)\\)", "");
value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
value = value.replaceAll("script", "");
value = cleanSqlKeyWords(value);
value = stripXSS(value);
return value;
}
private String cleanSqlKeyWords(String value) {
String paramValue = value;
for (String keyword : notAllowedKeyWords) {
if (paramValue.length() > keyword.length() + 4
&& (paramValue.contains(" " + keyword) || paramValue.contains(keyword + " ") || paramValue.contains(" " + keyword + " "))) {
paramValue = StringUtils.replace(paramValue, keyword, replacedString);
System.out.println(this.currentUrl + "已被过滤,因为参数中包含不允许sql的关键词(" + keyword + ")" + ";参数:" + value + ";过滤后的参数:" + paramValue);
}
}
return paramValue;
}
private String stripXSS(String value) {
//正则过滤关键字
if (value != null) {
// Avoid null characters
value = value.replaceAll("", "");
// Avoid anything between script tags
Pattern scriptPattern = Pattern.compile("(.*?)", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid anything in a src="http://www.yihaomen.com/article/java/..." type of expression
scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Remove any lonesome tag
scriptPattern = Pattern.compile("", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Remove any lonesome tag
scriptPattern = Pattern.compile("", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid eval(...) expressions
scriptPattern = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid expression(...) expressions
scriptPattern = Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid javascript:... expressions
scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid vbscript:... expressions
scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid οnlοad= expressions
scriptPattern = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid οnclick=
scriptPattern = Pattern.compile("onclick(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
}
return value;
}
}
第三:设置xss过滤器,filter
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
public class XssSpringFilter implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String requestURI = request.getRequestURI();
//System.out.println("--------------------->过滤器:请求地址" + requestURI);
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//跨域设置
if (response instanceof HttpServletResponse) {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
//通过在响应 header 中设置 ‘*’ 来允许来自所有域的跨域请求访问。
httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
//通过对 Credentials 参数的设置,就可以保持跨域 Ajax 时的 Cookie
//设置了Allow-Credentials,Allow-Origin就不能为*,需要指明具体的url域
//httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
//请求方式
httpServletResponse.setHeader("Access-Control-Allow-Methods", "*");
//(预检请求)的返回结果(即 Access-Control-Allow-Methods 和Access-Control-Allow-Headers 提供的信息) 可以被缓存多久
httpServletResponse.setHeader("Access-Control-Max-Age", "86400");
//首部字段用于预检请求的响应。其指明了实际请求中允许携带的首部字段
httpServletResponse.setHeader("Access-Control-Allow-Headers", "*");
}
//sql,xss过滤
if ("POST".equalsIgnoreCase(request.getMethod())) {
XSSRequestWrapper xssRequestBodyWrapper = new XSSRequestWrapper(request);
chain.doFilter(xssRequestBodyWrapper, response);
} else {
XSSRequestWrapper xssRequestWrapper = new XSSRequestWrapper(request);
chain.doFilter(xssRequestWrapper, response);
}
//System.out.println("--------------------->过滤器:结束" + requestURI);
}
@Override
public void destroy() {
}
}
第四:注册bean=“Filter”
/**
* 注册Filter
*/
@Bean
public FilterRegistrationBean xssSpringFilter(){
FilterRegistrationBean bean = new FilterRegistrationBean(new XssSpringFilter());
bean.addUrlPatterns("/*");
return bean;
}
第五:大功告成