说明
浏览器工作原理与实践专栏学习笔记
前言
支持页面中的第三方资源引用和 CORS 也带来了很多安全问题,其中最典型的就是 XSS 攻击。
什么是 XSS 攻击
XSS 全称是 Cross Site Scripting,为了与“CSS”区分开来,故简称 XSS,翻译过来就是“跨站脚本”。XSS 攻击是指黑客往 HTML 文件中或者 DOM 中注入恶意脚本,从而在用户浏览页面时利用注入的恶意脚本对用户实施攻击的一种手段。
恶意脚本能做的事情:
- 窃取 Cookie 信息
- 监听用户行为
- 修改 DOM
- 在页面内生成浮窗广告
- …
注入恶意脚本的三种方式
通常情况下,主要有存储型 XSS 攻击、反射型 XSS 攻击和基于 DOM 的 XSS 攻击三种方式来注入恶意脚本。
1. 存储型 XSS 攻击
存储型 XSS 攻击是怎么向 HTML 文件中注入恶意脚本的:
- 黑客利用站点漏洞将一段恶意 JavaScript 代码提交到网站的数据库中
- 用户向网站请求包含了恶意 JavaScript 脚本的页面
- 当用户浏览该页面的时候,恶意脚本就会将用户的 Cookie 信息等数据上传到服务器
典型例子:喜马拉雅存储型 XSS 漏洞
乌云网(由于某些原因被关停了)在 2015 年曝出来的,参见:https://bugs.shuimugan.com/bug/view?bug_no=138479
- 起因是在用户设置专辑名称时,服务器对关键字过滤不严格,导致黑客将恶意代码存储到漏洞服务器上。
- 然后用户打开了含有恶意脚本的页面,这段代码就会在用户的页面里执行,这样就可以窃取 Cookie 等数据信息。
- 恶意脚本可以通过 XMLHttpRequest 或者 Fetch 将用户的 Cookie 数据上传到黑客的服务器
- 黑客利用 Cookie 信息登录用户账户
2. 反射型 XSS 攻击
在一个反射型 XSS 攻击过程中,恶意 JavaScript 脚本属于用户发送给网站请求中的一部分,随后网站又把恶意 JavaScript 脚本返回给用户。当恶意 JavaScript 脚本在用户页面中被执行时,黑客就可以利用该脚本做一些恶意操作。
接下来我们搭建一个简单的 Node 服务程序来看看什么是反射型 XSS
- 在一个新的文件夹里打开控制台输入下面两个命令进行初始化操作,以及依赖安装
npm init
npm i express ejs
- 测试代码编写
路由代码:index.js
var express = require('express');
var app = express();
var ejs = require('ejs');
// 设置html引擎
app.engine('html', ejs.renderFile);
app.set('views', __dirname + '/');
// 设置视图引擎
app.set('view engine', 'html');
app.get('/', function(req, res, next) {
console.log('进入首页:哈哈哈哈');
res.render('index', {
title: '凯小默的 xss 测试页面',
xss: req.query.xss
});
});
app.listen(3000, () => {
console.log('服务启动成功!!!');
console.log("server listen on localhost:3000");
});
视图代码:index.html
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<h1><%= title %></h1>
<p>Welcome to <%= title %></p>
<div>
<!-- 将 URL 中 xss 参数的内容显示在页面 -->
<%- xss %>
</div>
</body>
</html>
- 启动服务,然后我们访问:
http://localhost:3000/?xss=kaimo666
node index.js
- 页面效果:xss参数被渲染到了页面
- 改变参数的值换成
http://localhost:3000/?xss=<script>alert('你被xss攻击了')</script>
- 看一下dom,发现恶意脚本插入到页面中了。
总结:从上面的例子我们可以看出,用户将一段含有恶意代码的请求提交给 Web 服务器,Web 服务器接收到请求时,又将恶意代码反射给了浏览器端,这就是反射型 XSS 攻击。
注意:Web 服务器不会存储反射型 XSS 攻击的恶意脚本,这是和存储型 XSS 攻击不同的地方。
3. 基于 DOM 的 XSS 攻击
基于 DOM 的 XSS 攻击是不牵涉到页面 Web 服务器的。主要是在 Web 资源传输过程或者在用户使用页面的过程中修改 Web 页面的数据。
比如:
- 通过 WiFi 路由器劫持的
- 通过本地恶意软件来劫持的
如何阻止 XSS 攻击
- 存储型 XSS 攻击和反射型 XSS 攻击都是需要经过 Web 服务器来处理,属于服务端的安全漏洞
- 基于 DOM 的 XSS 攻击是在浏览器端完成的,属于前端的安全漏洞
不同 XSS 攻击的共同点:首先往浏览器中注入恶意脚本,然后再通过恶意脚本将用户信息发送至黑客部署的恶意服务器上。
阻止 XSS 攻击的本质:通过阻止恶意 JavaScript 脚本的注入和恶意消息的发送来实现。
1. 服务器对输入脚本进行过滤或转码
比如:
code:<script>alert('你被xss攻击了')</script>
过滤:
code:
转码:
code:<script>alert('你被xss攻击了')</script>
2. 充分利用 CSP
CSP 功能:
- 限制加载其他域下的资源文件,这样即使黑客插入了一个 JavaScript 文件,这个 JavaScript 文件也是无法被加载的;
- 禁止向第三方域提交数据,这样用户数据也不会外泄;
- 禁止执行内联脚本和未授权的脚本;
- 还提供了上报机制,这样可以帮助我们尽快发现有哪些 XSS 攻击,以便尽快修复问题。
3. 使用 HttpOnly 属性
由于很多 XSS 攻击都是来盗用 Cookie 的,因此还可以通过使用 HttpOnly 属性来保护我们 Cookie 的安全。
通常服务器可以将某些 Cookie 设置为 HttpOnly 标志,HttpOnly 是服务器通过 HTTP 响应头来设置的。
比如:下面是打开 Google 时,HTTP 响应头中的一段:set-cookie 属性值最后使用了 HttpOnly 来标记该 Cookie。
set-cookie: NID=189=M8q2FtWbsR8RlcldPVt7qkrqR38LmFY9jUxkKo3-4Bi6Qu_ocNOat7nkYZUTzolHjFnwBw0izgsATSI7TZyiiiaV94qGh-BzEYsNVa7TZmjAYTxYTOM9L_-0CN9ipL6cXi8l6-z41asXtm2uEwcOC5oh9djkffOMhWqQrlnCtOI; expires=Sat, 18-Apr-2020 06:52:22 GMT; path=/; domain=.google.com; HttpOnly
使用 HttpOnly 标记的 Cookie 只能使用在 HTTP 请求过程中,所以无法通过 JavaScript 来读取这段 Cookie。
通过 Chrome 开发者工具来查看哪些 Cookie 被标记了 HttpOnly:比如下图里的 UserInfo 这个 Cookie 的 HttpOlny 属性是被勾选上的,所以 UserInfo 的内容是无法通过 document.cookie
是来读取的。
可以自己在控制台测试一下,输入 document.cookie
,然后 ctrl + f 去搜索 UserInfo 是找不到的。
因此一些比较重要的数据建议设置 HttpOnly 标志。