XSS, 即为(Cross Site Scripting), 中文名为跨站脚本, 是发生在目标用户的浏览器层面上的攻击方式,当渲染DOM树的过程成发生了不在预期内执行的JS代码时,就发生了XSS攻击。

XSS攻击方式

反射型 XSS

反射型XSS,也叫非持久型XSS,是指发生请求时,XSS代码出现在请求URL中,作为参数提交到服务器,服务器解析并响应。响应结果中包含XSS代码,最后浏览器解析并执行。

从概念上可以看出,反射型XSS代码是首先出现在URL中的,然后需要服务端解析,最后需要浏览器解析之后XSS代码才能够攻击。

例如:
使用express起一个web服务器,然后设置一下请求接口。通过ajax的GET请求将参数发往服务器,服务器解析成json后响应。将返回的数据解析后显示到页面上。(没有对返回的数据进行解码和过滤等操作。)

1
2
<textarea name="txt" id="txt" cols="80" rows="10">
<button type="button" id="test">测试</button>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//客户端代码
var test = document.querySelector('#test')
test.addEventListener('click', function () {
var url = `/test?test=${txt.value}` // 1. 发送一个GET请求
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
// 3. 客户端解析JSON,并执行
var str = JSON.parse(xhr.responseText).test
var node = `${str}`
document.body.insertAdjacentHTML('beforeend', node)
} else {
console.log('error', xhr.responseText)
}
}
}
xhr.open('GET', url, true)
xhr.send(null)
}, false)
1
2
3
4
5
6
7
8
9
10
//服务器代码
var express = require('express');
var router = express.Router();

router.get('/test', function (req, res, next) {
// 2. 服务端解析成JSON后响应
res.json({
test: req.query.test
})
})

现在我们通过给textarea添加一段有攻击目的的img标签,
<img src="null" onerror='alert(document.cookie)' />

现在,我们点击<测试>按钮,一个XSS攻击就发生了。

实际上,我们只是模拟攻击,通过alert获取到了个人的cookie信息。但是如果是黑客的话,他们会注入一段第三方的js代码,然后将获取到的cookie信息存到他们的服务器上。这样的话黑客们就有机会拿到我们的身份认证做一些违法的事情了。

存储型 XSS

存储型XSS,也叫持久型XSS,主要是将XSS代码发送到服务器并存储在服务器中(不管是数据库、内存还是文件系统等),在用户下次请求页面的时候服务器返回XSS代码并在浏览器中运行。
最典型的就是留言板XSS。用户提交了一条包含XSS代码的留言到数据库。当目标用户查询留言时,那些留言的内容会从服务器解析之后加载出来。浏览器发现有XSS代码,就当做正常的HTML和JS解析执行。XSS攻击就发生了。

DOM XSS

DOM XSS代码不需要服务器端的解析响应的直接参与,通常是通过浏览器端解析用户输入的内容并直接在页面执行导致的。

例如:

1
2
3
eval("var x = '" + location.hash + "'");
// url为
`https://www.examle.com/index.html#';alert(document.cookie);`

以下 API 均需要注意:

动态改变 DOM 的 API:

  • innerHTML/outerHTML
  • appendChild/replaceChild/insertBefore
  • setAttribute
  • document.write/document.writeln

动态代码执行:

  • document.execCommand
  • eval
  • setTimeout/setInterval
  • new Function()

用户输入来源:

  • location.href
  • location.hash
  • document.URL
  • document.cookie
  • localStorage
  • sessionStorage
  • indexedDB
  • window.opener

XSS危害

  1. 通过 document.cookie 盗取 cookie
  2. 使用 JS 或 CSS 破坏页面正常的结构、样式与功能,篡改页面
  3. 流量劫持(通过 window.location.href 跳转到其他页面)
  4. Dos攻击:利用合理的客户端请求来占用过多的服务器资源,从而使合法用户无法得到服务器响应
  5. 利用iframe、frame、XMLHttpRequest等方式,以(被攻击)用户的身份执行一些提交行为,或执行一些一般的如发微博、加好友、发私信等操作
  6. 利用可被攻击的域受到其他域信任的特点,以受信任来源的身份请求一些平时不允许的操作,如进行不当的投票活动

XSS防御

从以上的XSS攻击样例可以看出,我们不能原样地将用户输入的数据直接存到服务器,需要对数据进行一些处理。以上的代码出现的一些问题如下

  • 没有过滤危险的DOM节点。如具有执行脚本能力的script, 具有显示广告和色情图片的img, 具有改变样式的link, style, 具有内嵌页面的iframe, frame等元素节点。
  • 没有过滤危险的属性节点。如事件, style, src, href等
  • 没有对 cookie 设置 httpOnly 。

解决方法如下:

对cookie的保护

对重要的 cookie 设置 httpOnly , 防止客户端通过 document.cookie 读取 cookie 。

对用户输入数据的处理

  • 编码:不能对用户输入的内容都保持原样,对用户输入的数据进行字符实体编码。
  • 解码:原样显示内容的时候解码。
  • 过滤:把输入的一些不合法的字符过滤掉,从而保证安全性。如移除用户上传的DOM属性,如 onerror ,移除用户上传的 style、iframe、script 节点等。

设置 CSP

CSP (Content-Security-Policy)内容安全策略,是一个额外的安全层,通过指定有效域——即浏览器认可的可执行脚本的有效来源——使服务器管理者有能力减少或消除XSS攻击所依赖的载体。

设置 X-XSS-Protection

HTTP X-XSS-Protection 响应头是 Internet Explorer,Chrome 和 Safari 的一个特性,当检测到跨站脚本攻击(XSS)时,浏览器将停止加载页面。