前端面试系列【004】 - 请描述 XSS 的基本概念,攻击原理和防御措施

211 阅读3分钟

基本概念

先来看看 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

结语

更佳阅读体验:004 - 请描述 XSS 的基本概念,攻击原理和防御措施