国庆的前一天,突然有一个漏洞单接到我这里来,当时心里很着急,第一实习生小白,对于我们这种支付部门有漏洞不是很可怕,以前没见过,觉得有点吓人。第二,为什么是国庆的前一天呢,不能发版本。看了下,就是熟悉又不太熟悉的 Dom xss 漏洞。熟悉是因为以前书里经常见,不熟悉是因为以前没有实践过。
现象及解决办法
安全部门的同事说,它更改了 uin, 然后就可以输出 用户uin, 也就是俗称的 alert 出来。
大概是这样一个步骤
1 | document.cookie = "uin=<img src=x onerror=alert('')>" |
解决方法当然是换掉我不严谨的获取cookie的方法,正确获取 cookie 的方法应该如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17function getCookie(b) {
var filterXSS = function(e) {
if (!e) return e;
for (; e != unescape(e);) e = unescape(e);
for (var r = ["<", ">", "'", '"', "%3c", "%3e", "%27", "%22", "%253c", "%253e", "%2527", "%2522"], n = ["<", ">", "'", """, "%26%23x3c%3B", "%26%23x3e%3B", "%26%23x27%3B", "%26%23x22%3B", "%2526%2523x3c%253B", "%2526%2523x3e%253B", "%2526%2523x27%253B", "%2526%2523x22%253B"], a = 0; a < r.length; a++) e = e.replace(new RegExp(r[a], "gi"), n[a]);
return e
};
var a;
return filterXSS((a=document.cookie.match(RegExp("(^|;\\s*)"+b+"=([^;]*)(;|$)")))?unescape(a[2]):null)
}
探究原因
那么我的 Cookie 是怎么获取的呢?
1 | var ret = document.cookie.match(new RegExp("(?:^|;\\s)" + name + "=(.*?)(?:;\\s|$)")); |
为啥我的就不严谨了呢?
日常我们的cookie 是这样一种格式:1
ts_refer=ADTAGpay.index.header.paycenter; pgv_si=s3636090880; pgv_info=ssid=s9066946176; ts_last=pay.qq.com/; pgv_pvid=2986859684; ts_uid=8406093480
所以上面代码通过 = 和 ; 获得对应的 cookie , 似乎没有错,但是如果一遇到恶意攻击,没有对不合法字符进行任意转义就输出到页面上,就会造成 web 前端的安全大隐患。所以看到最上面我们的好方法里面,是有对不合法字符进行转义的。所以我们这样处理后,就会变成下面这样一个结果:
延伸
记得我刚来面试的时候,当时 qq 问了我获取 cookie 的方法,那时之前做项目写过获取 cookie 的方法,还是特别傻的方法,代码大概是这样的: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
29function getCookie(c_name)
{
if (document.cookie.length>0)
{
c_start=document.cookie.indexOf(c_name + "=")
if (c_start!=-1)
{
c_start=c_start + c_name.length+1
c_end=document.cookie.indexOf(";",c_start)
if (c_end==-1) c_end=document.cookie.length
return unescape(document.cookie.substring(c_start,c_end))
}
}
return ""
}
没错,就是正则也没用,直接去找 =
和 ;
之间的串是否与要查找的相同。这个方法在 w3cShool 上作为了标准方法,现在看来是误导人了。 当时 qq 问我有没有更好的方法,我说正则,但是正则还不能很快的写出来。那么这种方法除了效率不那么高以外,有没有上面提到的安全隐患呢?**做个实验:
1 | document.cookie = "a=123 b=other; b=678"; |
这个的意思是 cookie a 的值为 123 b=other, b的值为 678, 但是我们通过上面的 getCookie 方法 做实验时:1
2getCookie("b"); //输出 other
getCookie("a"); //输出 123 b=other
b的值很明显不正确了。这样就混淆了正确的 cookie。 所以这种方法也不是正确的方法,运用我们最上面提到的解决方法 可以很好的解决这个问题。
总结
还是实战出真知,继续前行!不怕犯错,积累经验。我当时跟师傅说我遇到了 dom xss 漏洞,师傅马上就让我去检查 cookie 获取的方法,连整个事情的经过就没问,就可以做出准确的判断,这就是老司机啊,向他学习。希望以后知道一些更多关于安全方面的实战。