Web 安全 - 跨站脚本攻击 XSS 三种类型及防御措施

311次阅读  |  发布于3年以前

XSS(Cross Site Scripting)是一种代码注入方式的跨站脚本攻击,为了与层叠样式表 CSS 区分,而简称 XSS。起因通常是由于黑客往 HTML、DOM 中插入了网站没有校验的恶意脚本,当用户浏览时,浏览器无法确认这些脚本是正常的还是注入的页面内容,当执行到这些恶意脚本时就会对用户进行 cookie 窃取、监听用户行为收集信息发往黑客服务器、会话劫持和修改页面 DOM 恶意攻击等。

恶意脚本的注入方式,归纳起来有三种类型:存储型 XSS 攻击、反射型 XSS 攻击、基于 DOM XSS 攻击

存储型 XSS 攻击

存储型 XSS 攻击是将恶意代码存储到网站服务器,如果出现漏洞传播速度、影响范围较为广泛,常见于社区、论坛等带有内容保存的系统中

首先黑客利用网站漏洞将恶意代码发送至服务器,而服务器未经校验就保存了,其他用户通过浏览器向网站服务器请求内容,浏览器解析恶意代码并执行,黑客的意图就成功了,接下来黑客可以通过脚本读取用户信息上传到黑客自己的服务器,或做一些其它的非法操作。

反射型 XSS 攻击

反射型 XSS 攻击是将恶意代码拼接在 URL 处,常见于网站搜索、跳转等,一个特点是需要黑客诱导用户点击 URL 实现代码注入

假设黑客在 URL 处拼接一段恶意代码,当请求到达网站服务端后,从 URL 取出这段恶意代码,如果不做任何处理直接拼接在 HTML 处返回,浏览器收到内容解析执行,混淆在正常内容中的恶意代码也会被执行。

不同于存储型,反射型是请求到达网站服务器后,不会存储到数据库。

使用 Node.js Express 框架和 pug 模版引擎模拟反射型 XSS 攻击,加深理解。

首先,创建一个项目 xss-reflection-type 并安装 express、pug 两个依赖。

$ mkdir xss-reflection-type
$ cd xss-reflection-type
$ npm init
$ npm i express pug -S

创建 app.js,这是我们的服务端,渲染模版数据返回。

// app.js
const express = require('express')
const path = require('path')
const app = express()
const PORT = 3000

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug')
app.get('/', (req, res) => {
  res.set('Set-Cookie', ['a=111'])
  res.render('index', { title: 'Hey', message: req.query.message })
})
app.listen(PORT, () => console.log(`Example app listening at http://localhost:${PORT}`))

模版路径为 views/index.pug,body 里面接收消息。

注意,使用 pug 模版引擎默认情况下,所有的属性都经过转义(即把特殊字符转换成转义序列)来防止诸如跨站脚本攻击之类的攻击方式

为了模拟 XSS 攻击,在模版渲染过程中我们先不对消息内容做转义,使用 != 代替 =,**你要知道这是不安全的,正常情况推荐你使用 ****=**。如果使用的 EJS 可以用 <%- 代替 <%= 实现不做转义处理。

// views/index.pug
html
  head
    title= title
  body
    h1!= message

运行 app.js 后,浏览器输入 http://localhost:3000/?message=<script>var cookie = document.cookie; alert(我是 XSS 攻击,你中招了 , cookie: ${cookie})</script> 回车后,页面上会弹出如下提示框。

image.png

DOM 型 XSS 攻击

DOM XSS 攻击不涉及网站服务器,通常是由于前端页面不严谨的代码产生的安全漏洞,导致注入了恶意代码

例如,在使用 .innerHTMLdocument.write()document.outerHTML 这些能够修改页面结构的 API 时要注意防范恶意代码,尽量使用 .textContent.setAttribute() 等。

例如,黑客构造带有恶意代码的 URL 诱导用户打开 http://www.xxx.com/index.html/?content=<script>alert('我是 DOM 型 XSS 攻击')</script>,浏览器收到请求后解析之行,如果使用 document.write() 未经转义输出,就可能遭到攻击。


<!DOCTYPE html>
<html>
  <body>
    <script>
      document.write('content: ' + decodeURIComponent(location.search));
    </script>
  </body>
</html>

XSS 防范

为了防止 XSS 攻击,我们需要验证用户的输入,做到有效检测。对输出的数据做编码,防止恶意脚本注入成功在浏览器端之行。

Reference

- END -

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8