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判断预防)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@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处理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
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中
具体实现功能代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
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 配置对象:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@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);
}
}
|
以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://tianjunwei.blog.csdn.net/article/details/62053577