XSS 是什么?
最近一个同学和我讨论一个问题,说到了 XSS 跨站攻击,我恰好对这块不是很熟,于是整理一下相关的资料,希望在编写互联网应用的时候多加注意。
同时,笔者会讨论具体的防护措施,希望大家都不会受到此类攻击的困扰。注意,下文涉及的技术细节仅供学习之用。
Overview
Cross Site Scripting (XSS) attacks 是一类代码注入攻击。攻击者利用了互联网应用的安全漏洞将恶意代码(通常是浏览器端脚本)插入正常可信的网站,甚至篡改网页内容。由于其他终端用户的浏览器认为脚本来自可信网站,因此直接执行,最终所有 cookies/session tokens 或其他敏感信息悉数被窃取,从而达到攻击其他终端用户(其他访问者)的目的。
而让这些攻击成为可能的 “安全漏洞”,或者说缺陷,在互联网应用中广泛存在,尤其是对前端接受用户输入的部分不做检查和编码的情况下。
Mechanisms
XSS 的攻击方式是怎样的?通常它有以下两个步骤:
- 数据通过不受信任的来源(最常见的是 Web 请求)进入 Web 应用程序;
- 可能存在恶意代码的数据包含在动态内容中发送给 Web 用户;
也就是说,只要浏览器引擎可以执行的代码(一段 JavaScript,HTML,Flash 代码等等),攻击者都可以发送并让受害者执行。
XSS 攻击主要分为两类:
Reflected XSS Attacks:顾名思义,就是指注入的脚本从 Web 服务器反射回来。
例如攻击者注入的脚本利用应用特性(例如不严谨的输入校验)嵌入在错误消息、搜索结果或任何其他响应,以链接 / 特制表单等形式传递给受害者。
当用户被诱骗点击恶意链接、提交特制表单,甚至只是浏览易受攻击的网站时,注入的代码就会传输到该网站,从而将攻击反射回用户的浏览器。然后浏览器执行代码,因为它来自“可信”服务器。Reflected XSS 有时也称为 Non-Persistent 或者 Type-I XSS(攻击通过单个请求/响应周期进行)。
Stored XSS Attacks:是指注入的脚本永久存储在目标服务器上,例如数据库、消息论坛、访问者日志、评论字段(其中评论和数据库最为常见)等。然后,受害者在请求存储的脚本时从服务器检索恶意脚本。Stored XSS 有时也称为 Persistent 或者 Type-II XSS。
(不常见)DOM-Based XSS Attacks:
Examples
再次重申,你不应该用这些手段去作出不当的行为,这里的内容仅供学习之用。
以 Reflected XSS Attack 为例。假设一个网站后端是 PHP 书写的,有个搜索的接口:
1 | http://my.project.com/a_form.html?search=stocks |
简化版的 PHP(危险之处是这个程序不经检查直接将有问题的):
1 | <?php echo 'You Searched: ' . $_GET["search"]; ?> |
如果攻击者不好好搜索正常的字符,而是搜索 <script>alert('malicious code here');</script>
怎么办?
这样浏览器会接受到完整的 JavaScript 内联标签并执行其中的代码。
例如攻击者可以将修改后的链接传播给不知情的用户:
1 | http://my.project.com/a_form.html?search=<script>alert('malicious code here');</script> |
如果代码中的是攻击者精心设计的有害代码,那么后果不堪设想。
再以 Stored XSS Attack 为例,假设有一个技术论坛的留言系统,没有任何输入检查措施,直接储存在数据库中,并将数据渲染在页面上。
那么攻击者可以写一段伪装的登录表单作为评论:
1 | <!-- 表单将数据发送给攻击者的网站 example.malicious.com --> |
那么在评论区就会出现一个可以交互的表单。如果攻击者用 CSS 或其他手段将这个表单包装起来,引诱用户输入信息,那么后果也很严重。
如果这个评论系统一直保留这个 vulnerability,那么这种方式轻则给该网站注入牛皮癣广告,重则严重泄漏用户信息。
当然,攻击者除了明目张胆使用上面的入侵代码,还可以:
故意写一个不存在的图片引用,让
onerror
执行恶意代码:<img src="http://url.to.file.which/not.exist" onerror=alert(document.cookie);>
;使用 URI encoded 表示方法绕过安全检查:
<IMG SRC=jAvascript:alert('test2')>
(注:UTF-8 中a=&\#X41
);使用 base64 加密并放在
META
tag 中:1
2<META HTTP-EQUIV="refresh"
CONTENT="0;url=data:text/html;base64,PHNjcmlwdD5hbGVydCgndGVzdDMnKTwvc2NyaXB0Pg">……
Consequences
无论是 stored 还是 reflected (或者是 DOM-based),XSS 攻击的后果都是相同的。它们的不同之处在于 effective payload 到达服务器的方式。
不要误以为 “只读” 的网站不易受到严重的反射型 XSS 攻击。XSS 带来的问题包括但不仅限于:
- 帐户信息、Session Cookies 泄露、账户劫持;
- 泄漏用户文件、安装木马程序;
- 舆论上:允许攻击者修改新闻稿或新闻项目的 XSS 漏洞可能会影响公司的股价或削弱消费者的信心。
- ……
互联网应用开发者应该如何防护
幸运的是,大多数现代的互联网应用程序前端框架都有防护 XSS 攻击的基本能力。
- React 默认情况下不允许使用 inner HTML;
- React 默认情况不允许解析
javascript:
或data:
开头的 URLs; - Angular 存在代码执行安全校验;
- Polymer 默认不使用 HTML literal;
- ……
所以开发者在前端应该:
- 不使用 React 标注危险的
dangerouslySetInnerHTML
元素属性; - 不使用 Angular
bypassSecurityTrustAs*
这类函数; - 尽量不使用 Polymer 的
inner-h-t-m-l
属性和htmlLiteral
函数; - 不使用过时的、被报告有缺陷的框架,及时更新;
- 自己不借助框架手写的话一定要注意测试此类问题,例如:
- 积极使用
DOMPurify
来进行 HTML Sanitization,处理输入; - 使用更安全的 HTML 属性,例如:SAFE SINKS;
- 积极使用
- 等等;
用户应该如何防护
- 不点击来源不明的链接;
- 不访问浏览器 / 安全软件明确提示危险的不可信网页;
- 不在不清楚安全性的网站上填写隐私信息;