0%

XSS原理及防御

XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。

XSS简介

XSS全称是Cross Site Scripting(为了和CSS进行区分,就叫XSS)即跨站脚本,是指恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。

XSS分类

反射型 XSS

反射型 XSS 的攻击步骤:

  1. 攻击者构造出特殊的 URL,其中包含恶意代码。
  2. 用户打开带有恶意代码的 URL 时,网站服务端将恶意代码从 URL 中取出,拼接在 HTML 中返回给浏览器。
  3. 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
  4. 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

反射型 XSS 漏洞常见于通过 URL 传递参数的功能,如网站搜索、跳转等。

由于需要用户主动打开恶意的 URL 才能生效,攻击者往往会结合多种手段诱导用户点击。

POST 的内容也可以触发反射型 XSS,只不过其触发条件比较苛刻(需要构造表单提交页面,并引导用户点击),所以非常少见。

存储型XSS

存储型 XSS 的攻击步骤:

  1. 攻击者将恶意代码提交到目标网站的数据库中。
  2. 用户打开目标网站时,网站服务端将恶意代码从数据库取出,拼接在 HTML 中返回给浏览器。
  3. 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
  4. 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

这种攻击常见于带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信等。

反射型 XSS 跟存储型 XSS 的区别是:反射型 XSS 的恶意代码存在 URL 里,存储型 XSS 的恶意代码存在数据库里。

DOM 型 XSS

DOM 型 XSS 的攻击步骤:

  1. 攻击者构造出特殊的 URL,其中包含恶意代码。
  2. 用户打开带有恶意代码的 URL。
  3. 用户浏览器接收到响应后解析执行,前端 JavaScript 取出 URL 中的恶意代码并执行。
  4. 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

DOM 型 XSS 跟前两种 XSS 的区别:DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞,而其他两种 XSS 都属于服务端的安全漏洞。

攻击方式

常用的XSS攻击手段和目的有:

  1. 盗用cookie,获取敏感信息。

  2. 利用植入Flash,通过crossdomain权限设置进一步获取更高权限;或者利用Java等得到类似的操作。

  3. 利用iframe、frame、XMLHttpRequest或上述Flash等方式,以(被攻击)用户的身份执行一些管理动作,或执行一些一般的如发微博、加好友、发私信等操作。

  4. 利用可被攻击的域受到其他域信任的特点,以受信任来源的身份请求一些平时不允许的操作,如进行不当的投票活动。

  5. 在访问量极大的一些页面上的XSS可以攻击一些小型网站,实现DDoS攻击的效果

XSS防御

防御XSS的七条原则

  1. 不要在页面中插入任何不可信数据,除非这些数已经据根据下面几个原则进行了编码
  2. 在将不可信数据插入到HTML标签之间时,对这些数据进行HTML Entity编码
  3. 在将不可信数据插入到HTML属性里时,对这些数据进行HTML属性编码
  4. 在将不可信数据插入到SCRIPT里时,对这些数据进行SCRIPT编码
  5. 在将不可信数据插入到Style属性里时,对这些数据进行CSS编码
  6. 在将不可信数据插入到HTML URL里时,对这些数据进行URL编码
  7. 使用富文本时,使用XSS规则引擎进行编码过滤

HttpOnly

HttpOnly 最早是由微软提出,并在 IE 6 中实现的,至今已经逐渐成为一个标准,各大浏览器都支持此标准。具体含义就是,如果某个 Cookie 带有 HttpOnly 属性,那么这一条 Cookie 将被禁止读取,也就是说,JavaScript 读取不到此条 Cookie,不过在与服务端交互的时候,Http Request 包中仍然会带上这个 Cookie 信息,即我们的正常交互不受影响。

输入检查

记住一点:不要相信任何输入的内容。

无论是不是做了安全校验,都必须进行过滤操作,而且需要后台配合过滤,如果后端的检查校验还做得不好,那就可能被攻破。

输入检查在更多的时候被用于格式检验,例如用户名只能以字母和数字组合,手机号码只能有 11 位且全部为数字,否则即为非法。

这些格式检查类似于白名单效果,限制输入允许的字符,让一下特殊字符的攻击失效。

目前网上有很多开源的 XSS Filter ,这些 XSS Filter 目前来说还是有些效果的,能只能检验输入内容,高级一点的还会匹配 XSS 特征,例如内容是否包含了 <script>javascript 等敏感字符,但是这些 XSS Filter 只是获取到了用户的输入内容,并不了解其上下文含义,很多时候会误过滤。

输出检查

不要以为在输入的时候进行过滤就万事大吉了,恶意攻击者们可能会层层绕过防御机制进行 XSS 攻击,一般来说,所有需要输出到 HTML 页面的变量,全部需要使用编码或者转义来防御。

HTMLEncode

针对 HTML 代码的编码方式是 HTMLEncode,它的作用是将字符串转换成 HTMLEntities

目前来说,为了对抗 XSS ,以下转义内容是必不可少的:

特殊字符 实体编码
& &amp;
< &lt;
> &gt;
&quot;
&#x27;
/ &#x2F;

JavaScriptEncode

JavaScriptEncodeHTMLEncode 的编码方式不同,它需要用 \ 对特殊字符进行转义。

在对抗 XSS 时,还要求输出的变量必须在引号内部,以免造成安全问题,可是很多开发者并没有这种习惯,这样只能使用更为严格的 JavaScriptEncode 来保证数据安全:除了数字,字符之外的所有字符,小于127的字符编码都使用十六进制 \xHH 的方式进行编码,大于用unicode(非常严格模式)。

正确的防御 XSS

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

如果网站使用了 MVC(MVVM) 结构,那么 XSS 就会发生在 View 层,也就是变量拼接到页面时产生的,所以在用户提交数据的时候进行输入检查,并不是真正在被攻击的地方做防御.

想要根治XSS问题,可以列出所有XSS可能发生的场景,再一一解决。

HTML 标签中输出

HTML 标签中直接输出变量,没有做任何处理,会导致 XSS

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

这种方式的解决方案是,所有需要输出到页面的元素全部通过 HTMLEncode

HTML 属性中输出

在和 HTML 标签中输出攻击方式类似,只不过输出的内容会自动闭合标签。

1
2
3
4
5
<div>$var</div>
<a href=# >$var</a>
<!-- "><img src=# onerror=alert(1)><" -->

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

这种方式的防御方法仍然是 HTMLEncode

<script> 标签中输出

假设我们的变量都在引号内部:

1
2
3
4
5
6
7
<script>
var x = "$var";
</script>

<script>
var x = "";alert(/xss/);"";
</script>

攻击者只需要闭合标签就能实行攻击,目前的防御方法为 JavaScriptEncode

CSS 中输出

CSS 中或者 style 标签或者 style attribute 中形成的攻击花样非常多,总体上类似于下面几个例子:

1
2
3
4
5
6
<style>@import url('http:xxxxx')</style>
<style>@import 'http:xxxxx'</style>
<style>li {list-style-image: url('xxxxxx')}</style>
<style>body {binding:url('xxxxxxxxxx')}</style>
<div style='background-image: url(xxxx)'></div>
<div style='width: expression(xxxxx)'></div>

要解决 CSS 的攻击问题,一方面要严格控制用户将变量输入style 标签内,另一方面不要引用未知的 CSS 文件,如果一定有用户改变 CSS 变量这种需求的话,可以使用 OWASP ESAPI 中的 encodeForCSS() 函数。

1
String safe = ESAPI.encoder().encodeForCSS(request.getParameter("input"));

URL 中输出

在地址张输出也比较复杂。一般来说 URLpath 或者 search 中进行攻击直接使用 URLEncode 即可。URLEncode 会将字符串转换为 %HH 的形式,类似空格就是 %20

可能的攻击方法就是:

1
2
3
4
5
6
<!-- 原始 URL -->
<a href="http://localhost/?test=$var">test</a>
<!-- 攻击 URL -->
<a href="http://localhost/?test=" onclick=alert(1)"">test</a>
<!-- URLEncode -->
<a href="http://localhost/?test=%22%20onclick%3balert%281%29%22"></a>

如果整个 URL 被用户控制,这时url的Protocal和Host是不能被URLEncode转义的。

一个 URL 的组成如下:

1
[Protocal][Host][Path][Search][Hash]

例如:

1
2
3
4
5
6
https://www.evil.com/a/b/c/test?abc=123#ssss
[Protocal] 对应 https://
[Host] 对应 www.evil.com
[Path] 对应 /a/b/c/test
[Search] 对应 ?abc=123
[Hash] 对应 #ssss

一般来说,如果变量是整个 URL ,则应该先检查变量是否以 http 开头,在此之后再对里面的变量进行 URLEncode

富文本处理

在一些网站,网站允许用户富含 HTML 标签的代码,比如文本里面要有图片、视频之类,这些文本展现出来全都是依靠 HTML 代码来实现。

那么,我们需要如何区分安全的 富文本XSS 攻击呢?

基本的思想就是:

  1. 首先进行输入检查,保证用户输入的是完整的 HTML 代码,而不是有拼接的代码
  2. 通过 htmlParser 解析出 HTML 代码的标签、属性、事件
  3. 富文本事件 肯定要被禁止,因为富文本 并不需要 事件 这种东西,另外一些危险的标签也需要禁止,例如: <iframe><script><base><form>
  4. 利用白名单机制,只允许安全的标签嵌入,例如:<a><img>div等,白名单不仅仅适用于标签,也适用于属性
  5. 过滤用户 CSS ,检查是否有危险代码

XSS攻击 百度百科

如何防止XSS攻击

防御XSS的七条原则

XSS的防御

《白帽子讲web安全》