基本概念
先来看看 wiki 的说明吧:
跨站脚本(英语:Cross-site scripting,通常简称为:XSS)是一种网站应用程序的安全漏洞攻击,是代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。这类攻击通常包含了 HTML 以及用户端脚本语言。
说得通俗一点,就是攻击者通过一些手法将可执行的脚本注入到网页中,在特定的情况下触发(可能是用户浏览网页,也可能是点击某些按钮),从而达到恶意攻击的行为。
攻击原理
这里引申出几个问题:
- 如何将脚本注入到网页中?
- 可能造成什么样的危害?
要回答这些问题,我们先来看一个简单的例子:
<body>
<div id="app"></div>
<input type="button" value="获取数据" onclick="test()" />
</body>
<script>
function test() {
const arr = ['1', '2', '3', '<img src="11" onerror="alert(\'xss\')" />']
const app = document.querySelector('#app')
arr.forEach((item) => {
const p = document.createElement('p')
p.innerHTML = item
app.append(p)
})
}
</script>
当点击按钮获取数据的时候,xss 就触发了:
这里本应展示在界面上的内容居然被当做脚本执行了,这显然是开发者不希望看到的。
清楚了基本原理,我们来到第一个问题。
如何将脚本注入到网页中?
显然,想要将恶意脚本注入到网页中,一定需要一个能够接受输入的地方,而在输入之后,根据数据是否被保存到服务器上,XSS 被分为两类:
- 反射型 XSS
- 存储型(持久型)XSS
从名字也能看出来,反射型 XSS 的恶意脚本并不会被保存,而存储型(持久型)XSS 的恶意脚本将会被长期保存在服务器。
那么具体要如何注入呢?
我们举一个非常简单的例子,假设下面是一个非常简陋的 todolist:
<body>
<input id="input" type="text" οnkeydοwn="onEnter()" />
<div id="app"></div>
</body>
<script>
const input = document.getElementById('input')
const app = document.getElementById('app')
input.onkeypress = function (event) {
if (event.which === 13) {
const p = document.createElement('p')
console.log(input.value)
p.innerHTML = input.value
app.append(p)
input.value = ''
}
}
</script>
来验证一下这个 todolist 的效果:
可以看到,现在它已经可以正常工作了。
这个时候,如果我们在 input
框中输入恶意脚本,会发生什么呢?
可见 XSS 就这样被触发了。因为输入的脚本并不会被保存到服务器上,不会持久存储,所以这里的 XSS 为反射型。
而存储型 XSS 则有可能在发表文章,评论等位置出现,因为这些数据是会被上传到服务器上保存下来的。
事实上,除了上述两种类型的 XSS 以外,还有一种较为特殊的类型:DOM Based XSS。
从效果上来说,它也属于反射型 XSS,但由于形成原因较为特殊,所以也被单独划分为一类,下面我们来看一个简单的例子:
<body>
<div id="t"></div>
<input type="text" id="text" value="">
<input type="button" id="s" value="search" onclick="test()">
</body>
<script>
function test() {
const str = document.querySelector('#text').value
document.querySelector('#t').innerHTML = '<a href="' + str + '" >查找结果</a>'
}
</script>
这个页面的作用是,如果 input
中输入的内容为一个可以跳转的链接,则点击查找结果之后会跳转到目标网页。(生成跳转链接的案例在平时工作中也是非常常见的。)
由于这里 str
是受用户控制的,那么如果用户用 "
和 //
将其前后截断,然后在中间插入恶意脚本,会造成什么样的后果呢?
显然,这也将造成 XSS,而这也就是 DOM Based XSS。
可能造成什么样的危害?
通过前面的介绍,我们知道,XSS 能够执行恶意脚本,主要是 JavaScript。那么,JS 能做到的事,通过 XSS 都能做到。
攻击者通常会通过这些恶意脚本做以下操作:
- 获取敏感信息
- 跳转恶意链接
- 结合浏览器漏洞提权种马
防御措施
知道了 XSS 是如何攻击的,那么防御自然也就有了头绪。
- 输入验证
- 校验常见的数字,url,电话,邮箱等
- 过滤敏感字符
- 开启浏览器 XSS 防御,如:http only cookie
- 输出编码
- HTML,JS,CSS,URL 编码
- 避免拼接 HTML,如
v-html
- 配置 CSP