Xss攻击防御

Xss 攻击示例

1
><marquee%20onwheel=alertxsser
1
><marquee%20onwheel=alertxsser>
1
<marquee%20onwheel=alertxsser>
1
></script><marquee onwheel=alert`xsser`>
1
><script>alert('XSS')

XSS 攻击的原理

攻击者直接在把html脚本当做参数传递到接口,然后接口依旧按照原样把参数返回。前端同学把返回的参数拍到页面,然后浏览器把html脚本参数当做正常的html执行,最终就导致了XSS攻击。

举个栗子:

发起如下的请求 –>

1
http://xxxxx?paramOne=><marquee%20onwheel=alertxsser>&paramTwo=bob

后端不对传入参数做处理,直接再拍回页面

1
2
3
<input id="xx" name="xx" type="text" value=${paramOne}/> 
最终的结果:
<input id="xx" name="xx" type="text" value="" />><marquee%20onwheel=alertxsser>

糟糕,><marquee%20onwheel=alertxsser> 这段代码会被当做正常的html执行,那么结果就是“页面开始滚动,或者页面出现一些奇怪的非正常页面展示”。

总结一下: XSS攻击就是攻击者把html作为参数传递给后端接口,后端接口把参数再原封不动的拍回页面展示。对于浏览器,它是无法识别参数是正常参数还是攻击脚本,它只能解释执行所有的html标签。

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
private static final String XSS_SCRIPT_PATTERN = "(?si)((<script.*?>[\\S\\s]*?<\\/script>)|(<script.*?/>)|(<.*?script>))";
private static final String XSS_STYLE_PATTERN = "<[\\s]*?style[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?style[\\s]*?>";
private static final String XSS_HTML_PATTERN = "((<[^>]+>) |(>.*<))";

private static final String XSS_KEY_WORD_SCRIPT = "script";
private static final String XSS_KEY_WORD_STYLE = "style";
private static final String XSS_KEY_WORD_HTML_LEFT_CORNER = "<";
private static final String XSS_KEY_WORD_HTML_RIGHT_CORNER = ">";


public static String detectXssAndReplaceJavaScript(String str) {
if (StringUtils.isEmpty(str)) {
return str;
}
String lowerCaseSrc = str.toLowerCase();

if (lowerCaseSrc.contains(XSS_KEY_WORD_SCRIPT)) {
Matcher matcher = Pattern.compile(XSS_SCRIPT_PATTERN).matcher(lowerCaseSrc);
if (matcher.find()) {
logger.info("detectXssAndReplaceJavaScript, type: script, str={}", str);
return "";
}
}

if (lowerCaseSrc.contains(XSS_KEY_WORD_HTML_LEFT_CORNER) || lowerCaseSrc.contains(XSS_KEY_WORD_HTML_RIGHT_CORNER)) {
Matcher matcher = Pattern.compile(XSS_HTML_PATTERN).matcher(lowerCaseSrc);
if (matcher.find()) {
// do escape
// lowerCaseSrc = lowerCaseSrc.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
logger.info("detectXssAndReplaceJavaScript, type: <>, originStr=[{}]", str);
return "";
}
}

if (lowerCaseSrc.contains(XSS_KEY_WORD_STYLE)) {
Matcher matcher = Pattern.compile(XSS_STYLE_PATTERN).matcher(lowerCaseSrc);
if (matcher.find()) {
logger.info("detectXssAndReplaceJavaScript, type: style, str={}", str);
return "";
}
}

return str;
}

/**
* 检查xss攻击,返回转义html标签后的字符串
* */
public static String detectAndEscapeHtmlXss(String str) {
if (StringUtils.isEmpty(str)) {
return str;
}

if (str.contains(XSS_KEY_WORD_HTML_LEFT_CORNER) || str.contains(XSS_KEY_WORD_HTML_RIGHT_CORNER)) {
Matcher matcher = Pattern.compile(XSS_HTML_PATTERN).matcher(str);
if (matcher.find()) {
// do escape
String var = str
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll("&", "&amps;")
.replaceAll("\"", "&quot;")
.replaceAll("\'", "&#x27;")
.replaceAll("/", "&#x2F;");
logger.info("detectXssAndReplaceJavaScript, type: <>, originStr=[{}], replaced=[{}]", str, var);
str = var;
}
}
return str;
}

XSS在项目中的实践落地

Servlet Filter + HttpServletRequestWrapper

Filter的作用是针对特定的uri进行拦截,并不是全局的的uri都过滤

HttpServletRequestWrapper主要是用于修改reqeust parameter的值。

下面是类图和时序图:

1560937935687