声明:本文并非本人原创。因本人水平有限,但是又想看一些深度不会过高,又有一定广度的文章。所以在浏览一些博客后,整理了这篇文章,供广大和我有同样需求的同学参考。
如有侵权,请联系本人,定立即删除。文章末尾附有摘取文章的链接,想深入了解的同学可以再深入学习一下。
目录
4. 其他 XSS 防范措施(还有很多,可以参考附录的第三篇文章)
一、什么是XSS注入?
Cross-Site Scripting(跨站脚本攻击)简称 XSS,是一种代码注入攻击。攻击者通过在目标网站上注入恶意脚本,使之在用户的浏览器上运行。利用这些恶意脚本,攻击者可获取用户的敏感信息如 Cookie、SessionID 等,进而危害数据安全。为了和 CSS 区分,这里把攻击的第一个字母改成了 X,于是叫做 XSS。
二、XSS注入有什么样的影响(XSS攻击的本质)?
- 恶意代码未经过滤,与网站正常的代码混在一起;浏览器无法分辨哪些脚本是可信的,导致恶意脚本被执行。
- 由于直接在用户的终端执行,恶意代码能够直接获取用户的信息,或者利用这些信息冒充用户向网站发起攻击者定义的请求。
- 在部分情况下,由于输入的限制,注入的恶意脚本比较短。但可以通过引入外部的脚本,并由浏览器执行,来完成比较复杂的攻击策略。
三、PoC(Proof of Concept)
我们可以用一段简单的代码,验证和检测漏洞的存在,这样的代码叫做 PoC(Proof of Concept)。验证 XSS 漏洞存在的 PoC 如下:
- <script>alert(/xss/)</script>
- <script>confirm('xss')</script>
- <script>prompt('xss')</script>
四、XSS注入分类
根据攻击的来源,XSS 攻击可分为存储型、反射型和 DOM 型三种。
类型 | 存储区* | 插入点* |
---|---|---|
存储型 XSS | 后端数据库 | HTML |
反射型 XSS | URL | HTML |
DOM 型 XSS | 后端数据库/前端存储/URL | 前端 JavaScript |
- 存储区:恶意代码存放的位置。
- 插入点:由谁取得恶意代码,并插入到网页上。
1、存储型 XSS
存储型 XSS 的攻击步骤:
- 攻击者将恶意代码提交到目标网站的数据库中。
- 用户打开目标网站时,网站服务端将恶意代码从数据库取出,拼接在 HTML 中返回给浏览器。
- 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
- 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
这种攻击常见于:
带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信等。
2、反射型 XSS
反射型 XSS 的攻击步骤:
- 攻击者构造出特殊的 URL,其中包含恶意代码。
- 用户打开带有恶意代码的 URL 时,网站服务端将恶意代码从 URL 中取出,拼接在 HTML 中返回给浏览器。
-
用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
-
恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
反射型 XSS 漏洞常见于:
通过 URL 传递参数的功能,如网站搜索、跳转等。
由于需要用户主动打开恶意的 URL 才能生效,攻击者往往会结合多种手段诱导用户点击。
POST 的内容也可以触发反射型 XSS,只不过其触发条件比较苛刻(需要构造表单提交页面,并引导用户点击),所以非常少见。
3、DOM 型 XSS
DOM 型 XSS 的攻击步骤:
- 攻击者构造出特殊的 URL,其中包含恶意代码。
- 用户打开带有恶意代码的 URL。
- 用户浏览器接收到响应后解析执行,前端 JavaScript 取出 URL 中的恶意代码并执行。
- 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
三种攻击方式的区别:
存储型 XSS 的恶意代码存在数据库里,反射型 XSS 的恶意代码存在 URL 里。DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞,而前两种属于服务端的安全漏洞。
五、XSS注入的方式有哪些?
- 在 HTML 中内嵌的文本中,恶意内容以 script 标签形成注入。[<script>alert(/xss/)</script>](蓝色部分为键入内容,这些方式是可以组合使用的,例如:先使用">将 input 的标签进行闭合,然后通过这些方式进行XSS注入)
- 在标签属性中,恶意内容包含引号,从而突破属性值的限制,注入其他属性或者标签。[<input type="text" οnkeydοwn="alert(/xss/)">]
- 在标签的 href、src 等属性中,包含
javascript:
等可执行代码。[<a href="javascript:alert(/xss/)">touch me!</a>] - 在 onload、onerror、onclick 等事件中,注入不受控制代码。[<img src='./smile.jpg' οnmοuseοver='alert(/xss/)'>]
- 在 style 属性和标签中,包含类似
background-image:url("javascript:...");
的代码(新版本浏览器已经可以防范)。[<div style="background-image:url(javascript:alert(/xss/))">]
六、XSS 攻击的预防
XSS 攻击有两大要素:
- 攻击者提交恶意代码。
- 浏览器执行恶意代码。
针对这两大要素,可以总结出下面四大类预防方案:
1. 输入过滤
输入过滤能够在某些情况下解决特定的 XSS 问题,但会引入很大的不确定性和乱码问题。当然,对于明确的输入类型,例如数字、URL、电话号码、邮件地址等等内容,进行输入过滤还是必要的。
产生的问题如下:
- 用户的输入内容可能同时提供给前端和客户端,而一旦经过了
escapeHTML()
,客户端显示的内容就变成了乱码(5 < 7
)。 -
在前端中,不同的位置所需的编码也不同。
-
当
5 < 7
作为 HTML 拼接页面时,可以正常显示:<div title="comment">5 < 7</div>
- 当
5 < 7
通过 Ajax 返回,然后赋值给 JavaScript 的变量时,前端得到的字符串就是转义后的字符。这个内容不能直接用于 Vue 等模板的展示,也不能直接用于内容长度计算。不能用于标题、alert 等。
-
2. 预防存储型和反射型 XSS 攻击
存储型和反射型 XSS 都是在服务端取出恶意代码后,插入到响应 HTML 里的,攻击者刻意编写的“数据”被内嵌到“代码”中,被浏览器所执行。
预防这两种漏洞,有两种常见做法:
- 改成纯前端渲染,把代码和数据分隔开。
- 对 HTML 做充分转义。
1) 纯前端渲染:
- 浏览器先加载一个静态 HTML,此 HTML 中不包含任何跟业务相关的数据。
- 然后浏览器执行 HTML 中的 JavaScript。
- JavaScript 通过 Ajax 加载业务数据,调用 DOM API 更新到页面上。
在纯前端渲染中,我们会明确的告诉浏览器:
下面要设置的内容是文本(.innerText
),还是属性(.setAttribute
),还是样式(.style
)等等。浏览器不会被轻易的被欺骗,执行预期外的代码了。
但纯前端渲染还需注意避免 DOM 型 XSS 漏洞(例如
onload
事件和href
中的javascript:xxx
等,请参考下文”预防 DOM 型 XSS 攻击“部分)。在很多内部、管理系统中,采用纯前端渲染是非常合适的。但对于性能要求高,或有 SEO 需求的页面,我们仍然要面对拼接 HTML 的问题。
2.)转义 HTML
如果拼接 HTML 是必要的,就需要采用合适的转义库,对 HTML 模板各处插入点进行充分的转义。
常用的模板引擎,如 doT.js、ejs、FreeMarker 等,对于 HTML 转义通常只有一个规则,就是把 & < > " ' /
这几个字符转义掉,确实能起到一定的 XSS 防护作用,但并不完善:
XSS 安全漏洞 | 简单转义是否有防护作用 |
---|---|
HTML 标签文字内容 | 有 |
HTML 属性值 | 有 |
CSS 内联样式 | 无 |
内联 JavaScript | 无 |
内联 JSON | 无 |
跳转链接 | 无 |
所以要完善 XSS 防护措施,我们要使用更完善更细致的转义策略。例如 Java 工程里,常用的转义库为 org.owasp.encoder
。
HTML 的编码是十分复杂的,在不同的上下文里要使用相应的转义规则。
3. 预防 DOM 型 XSS 攻击
DOM 中的内联事件监听器,如 location
、onclick
、onerror
、onload
、onmouseover
等,<a>
标签的 href
属性,JavaScript 的 eval()
、setTimeout()
、setInterval()
等,都能把字符串作为代码运行。如果不可信的数据拼接到字符串中传递给这些 API,很容易产生安全隐患,请务必避免。
4. 其他 XSS 防范措施(还有很多,可以参考附录的第三篇文章)
- HttpOnly:cookie 中设置了 HttpOnly 属性,那么通过js脚本将无法读取到 cookie 信息,这样能有效的防止 XSS 攻击,窃取 cookie 内容。
- secure:告诉浏览器仅在请求为https的时候发送 cookie ,当请求为 http 时不发送 cookie 。
response.addHeader("Set-Cookie", "uid=112; Path=/; Secure; HttpOnly");
七、绕过XSS过滤器的部分方法:
1. 大小写转换
可以将 payload 进行大小写转化。如下面两个例子。
<Img sRc='#' Onerror="alert(/xss/)" />
<a hREf="javaScript:alert(/xss/)">click me</a>
2. 使用引号
HTML 语言中对引号的使用不敏感,当我们的代码缺少引号时,某些浏览器会自动添加或补全,但是某些过滤函数是“锱铢必较”。
- <img src="#" οnerrοr="alert(/xss/)"/>
- <img src='#' οnerrοr='alert(/xss/)'/>
- <img src=# οnerrοr=alert(/xss/) />
3. [/]代替空格
可以利用左斜线代替空格。
<Img/sRc='#'/Onerror='alert(/xss/)' />
4. tab与回车
我们可以在一些位置添加 Tab(水平制表符,注意不是空格,空格是不可以的)和回车符,来绕过关键字检测。
- <Img/sRc='#'/Onerror ='alert(/xss/)' />
- <A hREf="j avascript:alert(/xss/)">click me!</a>
- <A hREf="j (换行) avascript:alert(/xss/)">click me!</a>
5. 对标签属性值进行转码
- 对应编码如下:
字母 | ASCII | 十进制编码 | 十六进制编码 | |
---|---|---|---|---|
1 | a | 97 | a | a |
2 | e | 101 | e | e |
3 | Tab | 9 | 	 | |
4 | 换行 | 10 | 
 | |
5 | 回车 | 13 | 
 | |
6 | SOH |  | ||
7 | STX |  |
- 我们可以将3-5插入到任意位置。
- 将6-7字符插入到头部位置。
例如:<a href=" ja v s	 c r ipt:alert(/xss/)">click me!</a>
6. base64加密与解密
先对 XSS 注入的代码进行 base64 加密,将加密后的代码放入 atob 函数中进行解密,最后可以再借助eval来执行被恶意注入的代码
<input type="text" name="p1" size="50" value="guangtailang" ><script>eval(atob('YWxlcnQoZG9jdW1lbnQuZG9tYWluKQ=='));</script> ">
7. 拆分跨站
- <script>z='alert'</script>
- <script>z=z+'(/xss/)'</script>
- <script>eval(z)</script>
- <script>alert(/xss/)</script>
摘自: