什么是XSS
XSS全称叫作Cross Site Scripting(跨站脚本攻击),就是恶意用户通过一些小技巧使一个正常的站点加入一些不正常的内容然后去执行。这里可以看到缩写是XSS,但是不是感觉不太对Cross Site Script的缩写不应该是css才对吗,你会发现这个css是不是一下子就联想到写页面样式的那个css了,所以是因为跟书写页面样式层叠样式表的css重名了才被称为XSS。这个攻击方式主要有两种“存储型XSS”和“反射信型CSS”,还有一种比较少见的叫作“DOM型XSS”。
存储型XSS
这种类型的攻击流流程是这样子
恶意用户:
- 恶意用户提交了恶意的内容到服务器
- 服务器不进行判断直接保存了提交进来的内容
正常用户:
- 正常用户访问服务器
- 服务器在不知情的情况下,响应了保存的的恶意内容,让正常用户遭到攻击
例
比如现在我有一个上传文章的服务器,如果服务器不做什么限制的话,如果恶意用户提交了以下内容
当正常用户去请求文章列表也获取文章信息时就会出现下面这种情况
可以看到这种情况是非常危险的,既然可以运行js代码,那就可以获取正常用户的cookie和其他的很多信息。
防御方法(node服务器)
可以使用一个第三方库
这个库可以将敏感字符串进行编码进行编码之后再发送到浏览器,浏览器就会把它当做是普通字符进行处理
const xss = require("xss");
const html = xss("<script>alert(1)</script>");
console.log(html); // <script>alert(1)</script>
可以看到,这个库自动吧<script>标签的尖角号给进行编码了,这样浏览器就会认为是普通的字符串,不会当成js代码来运行。所以服务器保存的时候,保存通过xss()函数处理过的结果即可。
这就是存储型XSS,恶意的内容被保存到了服务器数据库中,然后正常用户请求拿到了这个而已内容运行,但是防御的方式也很简单。XSS还有一种比较常见的型式那就是“反射型”,往下看。
反射型
恶意用户
- 恶意用户分享了一个正常网站的链接
- 将链接修改带有恶意内容
正常用户
- 正常用户点击了该链接
- 服务器在不知情的情况,把链接的恶意内容读取了出来,放进了页面中,让正常用户遭到攻击
例
假设我的服务器是这样写的,有这么个功能:可以将地址栏参数的值作为跳转地址
// express服务器
app.get("/article", (req, res, next) => {
res.render(path.resolve(__dirname, "./views/articles.ejs"), {
articles,
redirect: req.query.redirect
})
})
<!-- ejs模板 -->
<h1>反射型XSS</h1>
<a href="<%=redirect %> ">跳转至:<%=redirect%></a>
现在我把地址栏参数改成这样之后http://localhost:8002/article?redirect=><script></script>
可以看到网站运行了我们传递过去的js代码,查看网页源码就可以发现:
变成了类似于SQL注入的模式,生成了一个script标签。这里我们是通过模板引擎来渲染页面的,模板引擎一般都可以控制是渲染转义html标签后的内容还是渲染原内容,这里如果我们使用转义过后这种方式,链接地址这种写法就会失去作用。
左边是网页,右边是网页源码,可以看到我们对<script>的两个尖角号进行了转义。
这种方式我们可以简单的通过模板引擎的设置来轻松解决,但在a标签中运行js代码的方式不止这一个,还可以这样写http://localhost:8002/article?redirect=javascript:alert(1)。
虽然是点击后才会运行,但也有一定的风险。
防御方法
防御方法起始很简单,我们只需要将模板修改为这样
<a href="/<%=redirect %> ">跳转至:/<%=redirect%></a>
这样子修改后变成一个绝对的连接地址,就可以防止这种情况,只要不要让它以javascript开头即可
DOM型
由于这种类型比较少见,就不多多做记录了
恶意用户:
- 恶意用户通过特殊方式,向服务器中注入了一些dom元素,从而影响了服务器的dom结构
普通用户:
- 普通用户访问时,运行的是服务器的正常js代码
- 一些js代码是通过读取dom元素进行处理的,由于dom元素改变就可能导致读取dom元素错误
- 就比如我要计算a元素的宽高,但是现在有两个a元素是不是结果就跟预期的有一定差异
防御方法
只要在页面模板中全部使用转义后的内容就可以了,浏览器就不会把它当成一个dom元素。