一、XSS (Cross-Site Scripting),跨站脚本攻击,因为缩写和 CSS 重叠,所以只能叫 XSS。
原理
不需要你做任何的登录认证,它会通过合法的操作(如在 url 输入,在评论框中输入),向你的页面注入脚本(可能是 js, html 代码块等),当用户浏览该页时,嵌入 web 的脚本代码被执行,从而完成攻击。
影响
一、跨站脚本攻击有可能造成以下影响:
- 利用虚假输入表单骗取用户个人信息。
- 利用脚本窃取用户的 Cookie 值,被害者在不知情的情况下,帮助攻击者发送恶意请求。
- 显示伪造的文章或图片。
XSS 攻击手段/类型
持久型 XSS / 存储型 XSS
一、表单提交的数据存在恶意代码,被保存到目标网站的服务器中,当前端页面获得后端从数据库中读取的注入代码时,恰好将其渲染执行。
【示例】举个例子,对于评论功能来说,就得防范持久型 XSS 攻击,因为我可以在评论中输入以下内容 |
二、主要注入页面方式和非持久型 XSS 漏洞类似,只不过持久型的不是来源于 URL,referer,forms 等,而是来源于后端从数据库中读出来的数据 。持久型 XSS 攻击不需要诱骗点击,黑客只需要在提交表单的地方完成注入即可,但是这种 XSS 攻击的成本相对还是很高。
存储型 XSS 的条件
攻击成功需要同时满足以下几个条件:
●POST 请求提交表单后端没做转义直接入库。
● 后端从数据库中取出数据没做转义直接输出给前端。
● 前端拿到后端数据没做转义直接渲染成 DOM。
存储型 XSS 的特点
持久型 XSS 有以下几个特点:
● 持久性,植入在数据库(DB)中
● 盗取用户敏感私密信息
● 危害面广
存储型 XSS 的攻击步骤
存储型 XSS 的攻击步骤如下:
1. 攻击者将恶意代码提交到目标网站数据库中。
2. 用户打开目标网站时,网站服务器将恶意代码从数据库中取出,然后拼接到 html 中返回给浏览器中。
3. 用户浏览器接收到响应后解析执行,那么其中的恶意代码也会被执行。
4. 那么恶意代码执行后,就能获取到用户数据,比如上面的 cookie 等信息,那么把该 cookie 发送到攻击者网站中,那么攻击者拿到该 cookie 然后会冒充该用户的行为,调用目标网站接口等违法操作。
存储型 XSS 的防范
如何防范 :
1. 后端需要对提交的数据进行过滤。
2. 前端也可以做一下处理方式,比如对 script 标签,将特殊字符替换成 HTML 编码这些等。
3. 前端避免直接渲染,先转为文本
非持久型 XSS
反射型 XSS
一、发出请求时,xss 代码出现在 url 中,作为输入提交到服务器端,服务器端解析后响应,xss 代码随响应内容一起传回给浏览器,然后浏览器解析执行 xss 代码。
1、为什么叫反射型 XSS?
因为这种攻击方式的注入代码是从目标服务器通过错误信息,搜索结果等方式反射回来的。
2、为什么叫非持久性 XSS?
因为这种攻击方式只有一次性。
| 【示例】页面中含如下代码,攻击者可以直接通过 URL (类似:https://xxx.com/xxx?default=) 注入可执行的脚本代码。不过一些浏览器如 Chrome 其内置了一些 XSS 过滤器,可以防止大部分反射型 XSS 攻击。```javascript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| | | --- |
| 【示例】常见的反射型 XSS 是:恶意链接。比如我现在做一个 demo。在本地启动一个简单的服务器,然后在页面上点击一个链接后,比如如下代码:html 代码如下:
```javascript <!DOCTYPE html> <html> <head> <meta charset=utf-8> <meta name="referrer" content="never"> <title>csrf攻击</title> </head> <body> <div> <a href="http://localhost:3001/xss">xxs 攻击</a> <a href="http://localhost:3001/testcookie">testcookie 攻击</a> </div> </body> </html>
|
【示例】常见的反射型 XSS 是:恶意链接。比如我现在做一个 demo。在本地启动一个简单的服务器,然后在页面上点击一个链接后,比如如下代码:html 代码如下:
然后 node 中 app.js 代码如下:```javascript
const Koa = require(‘koa’);
const fs = require(‘fs’);
const path = require(‘path’);
const router = require(‘koa-router’)();
const koaBody = require(‘koa-body’);
const static = require(‘koa-static’);
const app = new Koa();
router.get(‘/‘, (ctx, next) => {
// 设置头类型, 如果不设置,会直接下载该页面
ctx.type = ‘html’;
// 读取文件
const pathUrl = path.join(__dirname, ‘/static/index.html’);
ctx.body = fs.createReadStream(pathUrl);
next();
});
router.get(‘/xss’, (ctx, next) => {
ctx.body = ‘‘;
});
router.get(‘/testcookie’, (ctx, next) => {
console.log(ctx.cookies.get(‘connect.sid’));
ctx.body = ‘‘;
next();
});
app.use(static(path.join(__dirname)));
app.use(router.routes());
app.use(router.allowedMethods());
app.listen(3001, () => {
console.log(‘server is listen in 3001’);
});
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
如上代码,当用户点击xxs 攻击恶意链接时候,页面会跳转到 http://localhost:3001/xss 攻击者预先准备的页面,然后会返回攻击者准备的js脚本,该js脚本就在浏览器中执行了,如下所示:<br /><br />![](https://img02.sogoucdn.com/v2/thumb/retype_exclude_gif/ext/auto/q/95/crop/xy/ai/t/0/?appid=122&url=cdn.nlark.com/yuque/0/2022/png/355497/1647220225733-e142aa42-1f9f-4405-8d7d-7d45180f4841.png)
然后我们点击 testcookie 该链接,也会调用node中的 router.get('/testcookie', (ctx, next) => {}) 这个请求获取到cookie,如下所示:
![](https://img02.sogoucdn.com/v2/thumb/retype_exclude_gif/ext/auto/q/95/crop/xy/ai/t/0/?appid=122&url=cdn.nlark.com/yuque/0/2022/png/355497/1647220238518-b756be01-097c-4567-8a42-154d52be52c8.png)
如上我们就可以很容易通过xss攻击拿到对方的cookie信息了。 | | --- |
**反射型XSS特征**<br />一、非持久型 XSS 漏洞攻击有以下几点**特征**:<br />●即时性,不经过服务器存储,直接通过 HTTP 的 GET 和 POST 请求就能完成一次攻击,拿到用户隐私数据。<br />●攻击者需要诱骗点击,必须要通过用户点击链接才能发起<br />●反馈率低,所以较难发现和响应修复<br />●盗取用户敏感保密信息
**反射型XSS攻击步骤**<br />一、反射型XSS攻击步骤:<br />1. 攻击者在url后面的参数中加入恶意攻击代码。 2. 当用户打开带有恶意代码的URL的时候,网站服务端将恶意代码从URL中取出,拼接在html中并且返回给浏览器端。 3. 用户浏览器接收到响应后执行解析,其中的恶意代码也会被执行到。 4. 攻击者通过恶意代码来窃取到用户数据并发送到攻击者的网站。攻击者会获取到比如cookie等信息,然后使用该信息来冒充合法用户的行为,调用目标网站接口执行攻击等操作。
**反射型XSS的防范:**<br />一、为了防止出现非持久型 XSS 漏洞,需要确保这么几件事情:<br />●Web 页面渲染的所有内容或者渲染的数据都必须来自于服务端。<br />●尽量不要从URL,document.referrer,document.forms等这种 DOM API 中获取数据直接渲染。<br />●尽量不要使用eval,new Function(),document.write(),document.writeln(),window.setInterval(),window.setTimeout(),innerHTML,document.createElement()等可执行字符串的方法。<br />●如果做不到以上几点,也必须对涉及 DOM 渲染的方法传入的字符串参数做 escape 转义(小程序跳转)。<br />●前端渲染的时候对任何的字段都需要做 escape 转义编码。
<a name="CKLh7"></a> ### DOM-based型攻击 一、利用dom本身的缺陷,进行攻击<br />我们客户端的js可以对页面dom节点进行动态的操作,比如插入、修改页面的内容。<br />比如说客户端从URL中提取数据并且在本地执行、如果用户在客户端输入的数据包含了恶意的js脚本的话,但是这些脚本又没有做任何过滤处理的话,那么我们的应用程序就有可能受到DOM-based XSS的攻击。
二、DOM XSS 是**基于文档对象模型的XSS**。<br />一般有如下DOM操作:<br /> 1. 使用document.write直接输出数据。 <br /> 2. 使用innerHTML直接输出数据。 <br /> 3. 使用location、location.href、location.replace、iframe.src、document.referer、window.name等这些。
| 【示例】
```javascript <script> document.body.innerHTML = "<a href='"+url+"'>"+url+"</a>"; </script>
|
假如对于变量 url 的值是:javascript:alert(‘dom-xss’); 类似这样的,那么就会收到 xss 的攻击了 |
因此对于 DOM XSS 主要是由于本地客户端获取的 DOM 数据在本地执行导致的。因此我们需要对 HTML 进行编码,对 JS 进行编码来防止这些问题产生。
| 【示例】 使用 document.write 直接输出导致浏览器解析恶意代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <!DOCTYPE html> <html> <head> <meta charset=utf-8> <meta name="referrer" content="never"> <title></title> </head> <body> <script type="text/javascript"> var s = location.search; // 返回URL中的查询部分(?之后的内容) // 为了方便演示,我们假如url是 如下这样的 // http://127.0.0.1/xsstest.html?url=javascript:alert('xsstest'); // 然后我们的是 s 的值就为如下: s = "?url=javascript:alert('xsstest')"; s = s.substring(1, s.length); // 返回整个查询内容 var url = ""; // 定义变量url if (s.indexOf("url=") > -1) { // 判断URL是否为空 var pos = s.indexOf("url=") + 4; // 过滤掉"url="字符 url = s.substring(pos, s.length); // 得到地址栏里的url参数 } else { url = "url参数为空"; } document.write('url: <a href="' + url + '">"' + url + '"</a>'); </script> </body> </html>
|
页面渲染完成后,点击弹窗如下所示:
|
| —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- |
| 【示例】使用 innerHTML 直接输出导致浏览器解析恶意代码```javascript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| 点击一样也会弹窗窗口的。也会一样执行xss攻击的。 | | --- |
| 【示例】使用 location/location.href/location.replace/iframe.src 造成的 XSS```javascript
<!DOCTYPE html> <html> <head> <meta charset=utf-8> <meta name="referrer" content="never"> <title></title> </head> <body> <script type="text/javascript"> var s = location.search; // 返回URL中的查询部分(?之后的内容) // 为了方便演示,我们假如url是 如下这样的 // http://127.0.0.1/xsstest.html?url=javascript:alert('xsstest'); // 然后我们的是 s 的值就为如下: s = "?url=javascript:alert('xsstest')"; s = s.substring(1, s.length); // 返回整个查询内容 var url = ""; // 定义变量url if (s.indexOf("url=") > -1) { // 判断URL是否为空 var pos = s.indexOf("url=") + 4; // 过滤掉"url="字符 url = s.substring(pos, s.length); // 得到地址栏里的url参数 } else { url = "url参数为空"; } </script> <div id='test'><a href=""></a></div> <script type="text/javascript"> location.href = url; </script> </body> </html>
|
刷新下页面,也会弹出窗口执行 xss攻击了。 |
| --- |
DOM 型 XSS 的攻击步骤
一、DOM 型 XSS 的攻击步骤如下:
1. 攻击者构造出特殊的 URL、在其中可能包含恶意代码。
2. 用户打开带有恶意代码的 URL。
3. 用户浏览器收到响应后解析执行。前端使用 js 取出 url 中的恶意代码并执行。
4. 执行时,恶意代码窃取用户数据并发送到攻击者的网站中,那么攻击者网站拿到这些数据去冒充用户的行为操作。调用目标网站接口执行攻击者一些操作。
XSS 防御手段
过滤 / CSP(Content-Security-Policy)
一、移除用户输入的和事件相关的属性
| 【示例】onerror 可以自动触发攻击,还有 onclick 等。
移除用户输入的 Style 节点、Script 节点、Iframe 等节点。
| |
| |
二、CSP 本质上就是建立白名单,开发者明确告诉浏览器哪些外部资源可以加载和执行。我们只需要配置规则,如何拦截是由浏览器自己实现的。我们可以通过这种方式来尽量减少 XSS 攻击。
三、通常可以通过两种方式来开启 CSP:
● 设置 HTTP Header 中的 Content-Security-Policy
● 设置 meta 标签的方式
| 【示例】这里以设置 HTTP Header 来举例:
● 只允许加载本站资源
Content-Security-Policy: default-src ‘self’
● 只允许加载 HTTPS 协议图片
Content-Security-Policy: img-src https://*
● 允许加载任何来源框架
Content-Security-Policy: child-src ‘none’
如需了解更多属性,请查看Content-Security-Policy 文档
| |
| |
四、对于这种方式来说,只要开发者配置了正确的规则,那么即使网站存在漏洞,攻击者也不能执行它的攻击代码,并且 CSP 的兼容性也不错。
编码 / 转义字符
一、HTML Entity 编码,对用户输入的数据进行编码
| 【示例】用户的输入永远不可信任的,最普遍的做法就是转义输入输出的内容,对于引号、尖括号、斜杠进行转义```javascript
function escape(str) {
str = str.replace(/&/g, ‘&’)
str = str.replace(/</g, ‘<’)
str = str.replace(/>/g, ‘>’)
str = str.replace(/“/g, ‘&quto;’)
str = str.replace(/‘/g, ‘'’)
str = str.replace(/`/g, ‘`’)
str = str.replace(///g, ‘/’)
return str
}
1 2 3 4 5 6 7 8
| | | --- |
| 【示例】但是对于显示富文本来说,显然不能通过上面的办法来转义所有字符,因为这样会把需要的格式也过滤掉。对于这种情况,通常采用白名单过滤的办法,当然也可以通过黑名单过滤,但是考虑到需要过滤的标签和标签属性实在太多,更加推荐使用白名单的方式。以下示例使用了 js-xss 来实现,可以看到在输出中保留了 h1 标签且过滤了 script 标签。```javascript const xss = require('xss') let html = xss('<h1 id="title">XSS Demo</h1><script>alert("xss");</script>') // -> <h1>XSS Demo</h1><script>alert("xss");</script> console.log(html)
|
| |
| |
cookie
将重要的 cookie 设置成 http only,这样就不能通过 js 获取到该 cookie 了
1、这是预防 XSS 攻击窃取用户 cookie 最有效的防御手段。Web 应用程序在设置 cookie 时,将其属性设为 HttpOnly,就可以避免该网页的 cookie 被客户端恶意 JavaScript 窃取,保护用户 cookie 信息。
校正
一、避免直接对 HTML Entity 进行解码,使用 DOM Parse 转换,校对不配对的 DOM 标签。