记一次实战 Dom XSS 漏洞

    国庆的前一天,突然有一个漏洞单接到我这里来,当时心里很着急,第一实习生小白,对于我们这种支付部门有漏洞不是很可怕,以前没见过,觉得有点吓人。第二,为什么是国庆的前一天呢,不能发版本。看了下,就是熟悉又不太熟悉的 Dom xss 漏洞。熟悉是因为以前书里经常见,不熟悉是因为以前没有实践过。


    现象及解决办法

    安全部门的同事说,它更改了 uin, 然后就可以输出 用户uin, 也就是俗称的 alert 出来。

    xss 漏洞

    大概是这样一个步骤

    1
    2
    document.cookie = "uin=<img src=x onerror=alert('')>"
    然后刷新了我的网页,由于我获取cookie的方法不严谨,这个时候就alert出来了。

    解决方法当然是换掉我不严谨的获取cookie的方法,正确获取 cookie 的方法应该如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    function 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 = ["&#x3c;", "&#x3e;", "&#x27;", "&#x22;", "%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
    2
    var ret = document.cookie.match(new RegExp("(?:^|;\\s)" + name + "=(.*?)(?:;\\s|$)"));
    return ret ? ret[1] : "";

    为啥我的就不严谨了呢?

    日常我们的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
    29
    function 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
    2
    getCookie("b"); //输出 other
    getCookie("a"); //输出 123 b=other

    b的值很明显不正确了。这样就混淆了正确的 cookie。 所以这种方法也不是正确的方法,运用我们最上面提到的解决方法 可以很好的解决这个问题。


    总结

    还是实战出真知,继续前行!不怕犯错,积累经验。我当时跟师傅说我遇到了 dom xss 漏洞,师傅马上就让我去检查 cookie 获取的方法,连整个事情的经过就没问,就可以做出准确的判断,这就是老司机啊,向他学习。希望以后知道一些更多关于安全方面的实战。