跨站脚本(XSS)注入攻击防御的最有效办法是,通过Filter过滤检查提交参数的合法性。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Spring MVC Xss Filter
XSS (Cross Site Scripting): 跨站脚本攻击, 是Web程序中最常见的漏洞。指攻击者在网页中嵌入客户端脚本(例如JavaScript), 当用户浏览此网页时,脚本就会在用户的浏览器上执行,从而达到攻击者的目的.比如获取用户的Cookie,导航到恶意网站,携带木马等。
一般现代应用MVC实现spring mvc的实现比较广泛,因此,本文章描述spring mvc 的实现xss filter。
第一步
在web.xml中配置filter:
xssHttpServletFilter
com.x.y.filter.XssHttpServletFilter
xssHttpServletFilter
/*
第二步
创建过滤器
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.filter.OncePerRequestFilter;
/**
* 包装原生servlet对象,处理xss问题
*
*/
public class XssHttpServletFilter extends OncePerRequestFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(XssHttpServletFilter.class);
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
try {
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
chain.doFilter(xssRequest, response);
} catch (Exception e) {
LOGGER.error("Xss过滤器,包装request对象失败");
chain.doFilter(request, response);
}
}
}
第三步
创建request包装对象
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
/**
* 请求包装对象 处理Xss
*/
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(xssEncode(name));
if (value != null) {
value = xssEncode(value);
}
return value;
}
/**
* 覆盖getParameterValues方法,将参数名和参数值都做xss过滤
*/
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
encodedValues[i] = xssEncode(values[i]);
}
return encodedValues;
}
/**
* 获取request的属性时,做xss过滤
*/
@Override
public Object getAttribute(String name) {
Object value = super.getAttribute(name);
if (null != value && value instanceof String) {
value = xssEncode((String) value);
}
return value;
};
/**
* 覆盖getHeader方法,将参数名和参数值都做xss过滤。
*/
@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 || s.isEmpty()) {
return s;
}
try {
HTMLFilter htmlFilter = new HTMLFilter();
String clean = htmlFilter.filter(s);
return clean;
} catch (NullPointerException e) {
return s;
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
/**
* 获取最原始的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;
}
}
第四步
引用 html filter 的实现。采用htmlfitler 开源实现:xss-html-filter
关键点
Spring mvc 解析参数时,使用方法:webRequest.getParameterValues(name)
获取参数,因此,request封装对象只有实现了getParameterValues(String parameter)方法,才会过滤到controller method 的入参。
Open Declaration Object org.springframework.web.method.annotation.RequestParamMethodArgumentResolver
.resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest) throws Exception
@Override
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest) throws Exception {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
MultipartHttpServletRequest multipartRequest =
WebUtils.getNativeRequest(servletRequest, MultipartHttpServletRequest.class);
Object arg;
if (MultipartFile.class.equals(parameter.getParameterType())) {
assertIsMultipartRequest(servletRequest);
Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
arg = multipartRequest.getFile(name);
}
else if (isMultipartFileCollection(parameter)) {
assertIsMultipartRequest(servletRequest);
Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
arg = multipartRequest.getFiles(name);
}
else if (isMultipartFileArray(parameter)) {
assertIsMultipartRequest(servletRequest);
Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
List multipartFiles = multipartRequest.getFiles(name);
arg = multipartFiles.toArray(new MultipartFile[multipartFiles.size()]);
}
else if ("javax.servlet.http.Part".equals(parameter.getParameterType().getName())) {
assertIsMultipartRequest(servletRequest);
arg = servletRequest.getPart(name);
}
else if (isPartCollection(parameter)) {
assertIsMultipartRequest(servletRequest);
arg = new ArrayList(servletRequest.getParts());
}
else if (isPartArray(parameter)) {
assertIsMultipartRequest(servletRequest);
arg = RequestPartResolver.resolvePart(servletRequest);
}
else {
arg = null;
if (multipartRequest != null) {
List files = multipartRequest.getFiles(name);
if (!files.isEmpty()) {
arg = (files.size() == 1 ? files.get(0) : files);
}
}
if (arg == null) {
String[] paramValues = webRequest.getParameterValues(name);
if (paramValues != null) {
arg = paramValues.length == 1 ? paramValues[0] : paramValues;
}
}
}
return arg;
}
相关内容参考:
跨站脚本(XSS)注入攻击:http://www.what21.com/sys/view/java_javaweb-summary_1456896125462.html
Java模拟跨站脚本(XSS)注入攻击案例:http://www.what21.com/sys/view/java_java-summary_1456896075656.html
Java防止跨站脚本(XSS)注入攻击:http://www.what21.com/sys/view/java_javaweb-summary_1456896125971.html
小奋斗文章
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~