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> 回车后,页面上会弹出如下提示框。
DOM 型 XSS 攻击
DOM XSS 攻击不涉及网站服务器,通常是由于前端页面不严谨的代码产生的安全漏洞,导致注入了恶意代码。
例如,在使用 .innerHTML、document.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 攻击,我们需要验证用户的输入,做到有效检测。对输出的数据做编码,防止恶意脚本注入成功在浏览器端之行。
确定性类型字段加强校验:当一些字段是确定性类型的,在输入内容时应按照相应规则加强校验,例如手机号、邮箱等信息。
HTML 模版转义:对于前后端一体的应用,拼接 HTML 模版这些也是必不可少的,应对 HTML 模版做好充分转义。一些常用的模版引擎:pug、ejs 这些默认都带有转义功能,来防止 XSS 攻击。
设置 httpOnly:禁止用户读取 cookie,就算注入恶意代码,也无法读取 cookie 信息冒充用户提交信息。
过滤和转码:关键字符做过滤或转码,如果是过滤,直接过滤掉指定的关键词,页面就不会展示了。如果是转码,不会过滤掉但也不会让其执行,例如 <script> 转义为 <script>。推荐一个库 js-xss,用于对用户输入的内容进行过滤,以避免遭受 XSS 攻。
CSP:一种内容安全策略,需要在服务端设置,在 “Web 安全系列” 中会单独做为一篇文章介绍。
版权声明:本文由[五月君]发表于
编程界