## XSS简介  

跨站脚本攻击 ，英文全称是Cross Site Script，本来缩写是CSS，但是为了和层叠样式表（Cascading Style Sheet，CSS）有所区别，所以在安全领域叫做“XSS”。  

XSS攻击，通常指黑客通过“HTML注入”篡改了网页，插入了恶意的脚本，从而在用户浏览网页时，控制用户浏览器的一种攻击。在一开始，这种攻击的演示案例是跨域的，所以叫做“s跨站脚本”。但是发展到今天，由于JavaScript的强大功能以及网站前端应用的复杂化，是否跨域已经不再重要。但是由于历史原因，XSS这个名字却一直保留下来。  

XSS长期以来被列为客户端Web安全中的头号大敌。因为XSS破坏力强大，且产生的场景复杂，难以一次性解决。现在业内达成的共识是：针对各种不同场景产生的XSS，需要区分情景对待。即便如此，复杂的应用环境仍然是XSS滋生的温床。  

那么，什么是XSS呢？看看下面的例子。  

假设一个页面把用户输入的参数直接输出到页面上：  

在正常情况下，用户向param提交的数据会展示到页面中，比如提交：  

会得到如下结果：  

正常的用户请求  

此时查看页面源代码，可以看到：  

但是如果提交一段HTML代码：  

会发现，alert（/xss/）在当前页面执行了：  

包含了XSS攻击的用户请求结果再查看源代码：  

用户输入的Script脚本，已经被写入页面中，而这显然是开发者所不希望看到的。  

上面这个例子，就是XSS的第一种类型：反射型XSS。  

XSS根据效果的不同可以分成如下几类。  

第一种类型：反射型XSS  

反射型XSS只是简单地把用户输入的数据“反射”给浏览器。也就是说，黑客往往需要诱使用户“点击”一个恶意链接，才能攻击成功。反射型XSS也叫做“非持久型XSS”（Non-persistent XSS）。  

第二种类型：存储型XSS  

存储型XSS会把用户输入的数据“存储”在服务器端。这种XSS具有很强的稳定性。  

比较常见的一个场景就是，黑客写下一篇包含有恶意JavaScript代码的博客文章，文章发表后，所有访问该博客文章的用户，都会在他们的浏览器中执行这段恶意的JavaScript代码。黑客把恶意的脚本保存到服务器端，所以这种XSS攻击就叫做“存储型XSS”。  

存储型XSS通常也叫做“持久型XSS”（Persistent XSS），因为从效果上来说，它存在的时间是比较长的。  

第三种类型：DOM Based XSS  

实际上，这种类型的XSS并非按照“数据是否保存在服务器端”来划分，DOM Based XSS从效果上来说也是反射型XSS。单独划分出来，是因为DOM Based XSS的形成原因比较特别，发现它的安全专家专门提出了这种类型的XSS。出于历史原因，也就把它单独作为一个分类了。  

通过修改页面的DOM节点形成的XSS，称之为DOM Based XSS。  

看如下代码：  

点击“write”按钮后，会在当前页面插入一个超链接，其地址为文本框的内容：  

在这里，“write”按钮的onclick事件调用了test()函数。而在test()函数中，修改了页面的DOM节点，通过innerHTML把一段用户数据当做HTML写入到页面中，这就造成了DOM based XSS。  

构造如下数据：  

输入后，页面代码就变成了：  

首先用一个单引号闭合掉href的第一个单引号，然后插入一个onclick事件，最后再用注释符“//”注释掉第二个单引号。  

点击这个新生成的链接，脚本将被执行：  

恶意脚本被执行  

实际上，这里还有另外一种利用方式——除了构造一个新事件外，还可以选择闭合掉 ${\tt<a>}$ 标签，并插入一个新的HTML标签。尝试如下输入：  

页面代码变成了：  

脚本被执行：  

恶意脚本被执行  

## XSS攻击进阶  

### 初探XSS Payload  

前文谈到了XSS的几种分类。接下来，就从攻击的角度来体验一下XSS的威力。  

XSS攻击成功后，攻击者能够对用户当前浏览的页面植入恶意脚本，通过恶意脚本，控制用户的浏览器。这些用以完成各种具体功能的  

恶意脚本，被称为“XSS Payload”。  

XSS Payload实际上就是JavaScript脚本（还可以是Flash或其他富客户端的脚本），所以任何JavaScript脚本能实现的功能，XSS Payload都能做到。  

一个最常见的XSS Payload，就是通过读取浏览器的Cookie对象，从而发起“Cookie劫持”攻击。  

Cookie中一般加密保存了当前用户的登录凭证。Cookie如果丢失，往往意味着用户的登录凭证丢失。换句话说，攻击者可以不通过密码，而直接登录进用户的账户。  

如下所示，攻击者先加载一个远程脚本：  

真正的XSS Payload写在这个远程脚本中，避免直接在URL的参数里写入大量的JavaScript代码。  

在evil.js中，可以通过如下代码窃取Cookie：  

这段代码在页面中插入了一张看不见的图片，同时把document.cookie对象作为参数发送到远程服务器。  

事实上，http://www.evil.com/log并不一定要存在，因为这个请求会在远程服务器的Web日志中留下记录：  

这样，就完成了一个最简单的窃取Cookie的XSS Payload。  

如何利用窃取的Cookie登录目标用户的账户呢？这和“利用自定义Cookie访问网站”的过程是一样的，参考如下过程。  

在Firefox中访问用户的百度空间，登录后查看当前的Cookie：  

查看当前页面的Cookie值  

然后打开IE，访问同一个页面。此时在IE中，用户是未登录状态：  

用户处于未登录状态  

将Firefox中登录后的Cookie记录下来，并以之替换当前IE中的Cookie。重新发送这个包：  

使用同一Cookie值重新发包  

通过返回的页面可以看到，此时已经登录进该账户：  

返回登录后的状态页面  

验证一下，把返回的HTML代码复制到本地打开后，可以看到右上角显示了账户信息相关的数据：  

返回页面是已登录状态  

所以，通过XSS攻击，可以完成“Cookie劫持”攻击，直接登录进用户的账户。  

这是因为在当前的Web中，Cookie一般是用户登录的凭证，浏览器发起的所有请求都会自动带上Cookie如果Cookie没有绑定客户端信息，当攻击者窃取了Cookie后，就可以不用密码登录进用户的账户。  

Cookie的“HttpOnly”标识可以防止“Cookie劫持”，我们将在稍后的章节中再具体介绍。  

### 强大的XSS Payload  

上节演示了一个简单的窃取Cookie的XSS Payload。在本节中，将介绍一些更为强大的XSS Payload。  

“Cookie劫持”并非所有的时候都会有效。有的网站可能会在Set-Cookie时给关键Cookie植入HttpOnly标识；有的网站则可能会把Cookie与客户端IP绑定（相关内容在“XSS的防御”一节中会具体介绍），从而使得XSS窃取的Cookie失去意义。  

尽管如此，在XSS攻击成功后，攻击者仍然有许多方式能够控制用户的浏览器。  