XSS攻击
Published in:2023-06-29 | category: 前端 网络安全

一、XSS (Cross-Site Scripting),跨站脚本攻击,因为缩写和 CSS 重叠,所以只能叫 XSS。

原理

不需要你做任何的登录认证,它会通过合法的操作(如在 url 输入,在评论框中输入),向你的页面注入脚本(可能是 js, html 代码块等),当用户浏览该页时,嵌入 web 的脚本代码被执行,从而完成攻击。

影响

一、跨站脚本攻击有可能造成以下影响:

  1. 利用虚假输入表单骗取用户个人信息。
  2. 利用脚本窃取用户的 Cookie 值,被害者在不知情的情况下,帮助攻击者发送恶意请求。
  3. 显示伪造的文章或图片。

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>&lt;script&gt;alert("xss");&lt;/script&gt;
console.log(html)

| |
| |

将重要的 cookie 设置成 http only,这样就不能通过 js 获取到该 cookie 了
1、这是预防 XSS 攻击窃取用户 cookie 最有效的防御手段。Web 应用程序在设置 cookie 时,将其属性设为 HttpOnly,就可以避免该网页的 cookie 被客户端恶意 JavaScript 窃取,保护用户 cookie 信息。
image.png

校正

一、避免直接对 HTML Entity 进行解码,使用 DOM Parse 转换,校对不配对的 DOM 标签。

Prev:
http与https
Next:
密码重置漏洞