使用springMVC通过Filter实现防止xss注入
springmvc filter防止xss注入
跨站脚本工具(cross 斯特scripting),为不和层叠样式表(cascading style sheets,css)的缩写混淆,故将跨站脚本攻击缩写为xss。
恶意攻击者往web页面里插入恶意scriptscript代码,当用户浏览该页之时,嵌入其中web里面的script代码会被执行,从而达到恶意攻击用户的目的。
防止xss攻击简单的预防就是对request请求中的一些参数去掉一些比较敏感的脚本命令。
原本是打算通过springmvc的handlerinterceptor机制来实现的,通过获取request然后对request中的参数进行修改,结果虽然值修改了,但在controller中获取的数值还是没有修改的。没办法就是要filter来完成。
简单来说就是创建一个新的httprequest类xsslhttpservletrequestwrapper,然后重写一些get方法(获取参数时对参数进行xss判断预防)。
@webfilter(filtername="xssmyfilter",urlpatterns="/*") public class myxssfilter implements filter{ @override public void init(filterconfig filterconfig) throws servletexception { } @override public void dofilter(servletrequest request, servletresponse response, filterchain chain) throws ioexception, servletexception { xsslhttpservletrequestwrapper xssrequest = new xsslhttpservletrequestwrapper((httpservletrequest)request); chain.dofilter(xssrequest , response); } @override public void destroy() { } }
xss代码的过滤是在xsslhttpservletrequestwrapper中实现的,主要是覆盖实现了getparameter,getparametervalues,getheader这几个方法,然后对获取的value值进行xss处理。
public class xsslhttpservletrequestwrapper extends httpservletrequestwrapper { httpservletrequest xssrequest = null; public xsslhttpservletrequestwrapper(httpservletrequest request) { super(request); xssrequest = request; } @override public string getparameter(string name) { string value = super.getparameter(replacexss(name)); if (value != null) { value = replacexss(value); } return value; } @override public string[] getparametervalues(string name) { string[] values = super.getparametervalues(replacexss(name)); if(values != null && values.length > 0){ for(int i =0; i< values.length ;i++){ values[i] = replacexss(values[i]); } } return values; } @override public string getheader(string name) { string value = super.getheader(replacexss(name)); if (value != null) { value = replacexss(value); } return value; } /** * 去除待带script、src的语句,转义替换后的value值 */ public static string replacexss(string value) { if (value != null) { try{ value = value.replace("+","%2b"); //'+' replace to '%2b' value = urldecoder.decode(value, "utf-8"); }catch(unsupportedencodingexception e){ }catch(illegalargumentexception e){ } // avoid null characters value = value.replaceall("\0", ""); // avoid anything between script tags pattern scriptpattern = pattern.compile("<script>(.*?)</script>", pattern.case_insensitive); value = scriptpattern.matcher(value).replaceall(""); // avoid anything in a src='...' 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 </script> tag scriptpattern = pattern.compile("</script>", pattern.case_insensitive); value = scriptpattern.matcher(value).replaceall(""); // remove any lonesome <script ...> tag scriptpattern = pattern.compile("<script(.*?)>", 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 alert:... expressions scriptpattern = pattern.compile("alert", 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(""); scriptpattern = pattern.compile("vbscript[\r\n| | ]*:[\r\n| | ]*", pattern.case_insensitive); value = scriptpattern.matcher(value).replaceall(""); } return filter(value); } /** * 过滤特殊字符 */ public static string filter(string value) { if (value == null) { return null; } stringbuffer result = new stringbuffer(value.length()); for (int i=0; i<value.length(); ++i) { switch (value.charat(i)) { case '<': result.append("<"); break; case '>': result.append(">"); break; case '"': result.append("""); break; case '\'': result.append("'"); break; case '%': result.append("%"); break; case ';': result.append(";"); break; case '(': result.append("("); break; case ')': result.append(")"); break; case '&': result.append("&"); break; case '+': result.append("+"); break; default: result.append(value.charat(i)); break; } } return result.tostring(); } }
springmvc 防止xss 工具(常规方式)
要求:
xss过滤请求的参数:content-type为 json(application/json)
springmvc 对于application/json 转换处理说明:
spring mvc默认使用mappingjackson2httpmessageconverter转换器,
而它是使用jackson来序列化对象的,如果我们能 将jackson的序列化和反序列化过程修改,加入过滤xss代码,并将其注册到mappingjackson2httpmessageconverter中
具体实现功能代码:
import java.io.ioexception; import org.apache.commons.text.stringescapeutils; import com.fasterxml.jackson.core.jsonparser; import com.fasterxml.jackson.core.jsonprocessingexception; import com.fasterxml.jackson.databind.deserializationcontext; import com.fasterxml.jackson.databind.deser.std.stddeserializer; /** * 反序列化 * */ public class xssdefaultjsondeserializer extends stddeserializer<string> { public xssdefaultjsondeserializer(){ this(null); } public xssdefaultjsondeserializer(class<string> vc) { super(vc); } @override public string deserialize(jsonparser jsonparser, deserializationcontext ctxt) throws ioexception, jsonprocessingexception { // todo auto-generated method stub //return stringescapeutils.escapeecmascript(jsonparser.gettext()); return stringescapeutils.unescapehtml4(jsonparser.gettext()); } }
springmvc 配置对象:
@configuration @enablewebmvc public class spingmvcconfig extends webmvcconfigureradapter { @override public void configuremessageconverters(list<httpmessageconverter<?>> converters) { super.configuremessageconverters(converters); // todo auto-generated method stub simplemodule module = new simplemodule(); // 反序列化 module.adddeserializer(string.class, new xssdefaultjsondeserializer()); // 序列化 module.addserializer(string.class, new xssdefaultjsonserializer()); objectmapper mapper = jackson2objectmapperbuilder.json().build(); // 注册自定义的序列化和反序列化器 mapper.registermodule(module); mappingjackson2httpmessageconverter converter = new mappingjackson2httpmessageconverter(mapper); converters.add(converter); } }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。