导读: 最近公司项目上突然出现一个 DOM 型的 XSS 安全问题
,由于之前从没有接触过,本次就在此了解一下~
XSS 简单介绍
XSS
全称是 Cross Site Script
,即 跨站脚本
,但是在缩写上为了不和 层叠样式表(Cascading Style Sheets,缩写 CSS)
重复,所以才改名的 XSS
。
攻击者通常会向 Web 页面的 input 表单、URL、留言板等位置(即 HTML 注入)
插入恶意 JavaScript(JS)
代码,导致 用户或管理员
在访问的时候触发,从而达到攻击者控制用户浏览器的目的。
在一开始,这种攻击的演示案例是跨域的,所以叫 “跨站脚本”
。但是发展到今天,由于 Javascript 的强大功能以及网站前端应用的复杂化,是否跨域已经不再重要。但是由于历史原因,这个名字保留了下来。
XSS 原理
服务器对用户提交的数据过滤不严,导致浏览器把用户的输入当成了 JS 代码并直接返回给客户端执行,从而实现对客户端的攻击目的。
XSS 类型
反射型 XSS(非持久型)
反射型 XSS 是非持久型 XSS,攻击相对于受害者而言是一次性的
。
具体表现在受害者点击了含有的恶意 JavaScript
脚本的 url
,恶意代码并没有保存在目标网站,而 Web 应用程序只是 不加处理
的把该恶意脚本 “反射”
回受害者的浏览器而使受害者的浏览器执行相应的脚本。
存储型 XSS(持久型)
存储型 XSS 是持久型 XSS,由于数据由用户提交写入了数据库,再次取出该数据即会遭受攻击
。
具体表现是应用程序通过 Web 请求获取不可信赖的数据,在 未检验数据
是否存在 XSS 代码的情况下,便将其 存入数据库
;当下一次从数据库中获取该数据时程序也未对其进行过滤,页面再次执行 XSS 代码持续攻击用户。
存储型 XSS
漏洞大多出现在 留言板、评论区
,用户提交了包含 XSS 代码的留言到数据库,当目标用户查询留言时,那些留言的内容会从服务器解析之后加载出来。
DOM 型 XSS(非持久型)
DOM(Document Object Model)是非持久型 XSS,不与服务端交互,仅通过 DOM 操作前端代码进行的攻击
。
具体表现是一个平台和语言都中立的接口,可以使程序和脚本能够动态访问和更新文档的内容、结构以及样式,DOM 型 XSS
简单理解就是不与后台服务器产生数据交互,是一种通过 DOM 操作前端代码输出的时候产生的问题。
总结
修复 XSS 安全问题
引用三方库:xss
首先使用 npm
安装库:
npm install xss
在 Node.js
中使用:
var xss = require("xss");
var html = xss('<script>alert("xss");</script>');
console.log(html);
在浏览器端使用:
// Shim 模式 -------------
<script src="https://rawgit.com/leizongmin/js-xss/master/dist/xss.js"></script>
<script>
// 使用函数名 filterXSS,用法一样
var html = filterXSS('<script>alert("xss");</scr' + "ipt>");
alert(html);
</script>
// AMD 模式 -------------
<script>
require.config({
baseUrl: "./",
paths: {
xss: "https://rawgit.com/leizongmin/js-xss/master/dist/xss.js",
},
shim: {
xss: { exports: "filterXSS" },
},
});
require(["xss"], function (xss) {
var html = xss('<script>alert("xss");</scr' + "ipt>");
alert(html);
});
</script>
在 vue2.x
中使用:
<template>
<div v-html="message"></div>
</template>
<script>
import xss from 'xss'
// message 原始数据
this.message = `执行以下代码:<img scr=1 onerror=alert(1) />`
// 更新 message 数据
const newMsg = xss(this.message)
if (newMsg) {
this.message = newMsg
}
</script>
网上有网友使用了更优的方案:CSDN - vue 项目 v-html 存在植入 xss 攻击怎么解决
通过在编译前将从 vue-loader
传入的 compilerOptions.directives
和 baseOptions.directives
进行了合并,这样就能覆盖 html
指令。
未验证,谨慎使用。
// main.js ---------
import xss from 'xss';
Vue.prototype.xss = xss
// vue.config.js ----------
chainWebpack: config => {
config.module
.rule("vue")
.use("vue-loader")
.loader("vue-loader")
.tap(options => {
options.compilerOptions.directives = {
html(node, directiveMeta) {
(node.props || (node.props = [])).push({
name: "innerHTML",
value: `xss(_s(${directiveMeta.value}))`
});
}
};
return options;
});
}
引用三方库:Dompurify
首先使用 npm
安装库:
npm install dompurify
在 vue2.x
中使用:
<template>
<div v-html="message"></div>
</template>
<script>
import DOMPurify from 'dompurify'
// message 原始数据
this.message = `执行以下代码:<img scr=1 onerror=alert(1) />`
// 更新 message 数据
const newMsg = DOMPurify.sanitize(this.message)
if (newMsg) {
this.message = newMsg
}
</script>
实测效果:
onerror=alert(1)
代码会被过滤移除。
引用三方库:vue-dompurify-html
首先使用 npm
安装库:
npm install vue-dompurify-html
npm install vue-dompurify-html@4.1.4
在 vue2.x
中使用:
// main.js 文件中 ----------
import { createApp } from 'vue';
import App from './App.vue';
import VueDOMPurifyHTML from 'vue-dompurify-html';
const app = createApp(App);
app.use(VueDOMPurifyHTML);
app.mount('#app');
// 目标文件中,将 v-html 替换成 v-dompurify-html ------------
<template>
<div v-dompurify-html="message"></div>
</template>
<script>
// message 原始数据
this.message = `执行以下代码:<img scr=1 onerror=alert(1) />`
</script>
注意点: 1、如果是
Vue3.x
,需要使用vue-dompurify-html 5.x
以上的版本; 2、如果是Vue2.x
,需要使用vue-dompurify-html 4.x
,建议使用v4.1.4
。
其它解决方案:字符替换
核心点:是将 <>
转义替换成其他字符样式,从而避开 v-html
识别成标签问题。
可以参考:CSDN - vue 项目 v-html 存在植入 xss 攻击怎么解决
// 此处直接挪用的作者代码
let obj = {
name: "asdfasd <img onerror='alert(1)'",
age: "模拟2 <img onerror='alert(1)'",
}
Object.keys(obj).forEach((key,i) => {
obj[key] = obj[key].replace(/</g,'<')
});
其它资料
1、以下为需过滤的常见字符:
[1] |(竖线符号)
[2] & (& 符号)
[3] ;(分号)
[4] $(美元符号)
[5] %(百分比符号)
[6] @(at 符号)
[7] '(单引号)
[8] "(引号)
[9] \'(反斜杠转义单引号)
[10] \"(反斜杠转义引号)
[11] <>(尖括号)
[12] ()(括号)
[13] +(加号)
[14] CR(回车符,ASCII 0x0d)
[15] LF(换行,ASCII 0x0a)
[16] ,(逗号)
[17] \(反斜杠)
2、在请求返回页面关键字符进行转义;
[1] “ (双引号):"
[2] ’ (单引号):&apos
[3] &(&符号):&
[4] <(左尖括号):<
[5] >(右尖括号):>
参考链接
- Github - xss
- Github - Dompurify
- Github - vue-dompurify-html
- Segmentfault - 前端安全系列(一):如何防止 XSS 攻击?
- CSND - XSS 漏洞原理、分类、危害及防御
- 微信公众号 - XSS 漏洞总结
- CSDN - vue 项目 v-html 存在植入 xss 攻击怎么解决
- CSDN - 11-vue-dompurify-html 的使用及使用过程中的问题解决
版权声明
原文作者:苜蓿鬼仙(苜蓿、jijiucheng)
原文链接:GitHub.io - 苜蓿鬼仙 - 【前端】XSS 安全问题
发表日期:2024/10/29 16:00:00
更新日期:2024/10/29 16:00:00
GitHub:GitHub - jijiucheng
个人博客:GitHub.io - 苜蓿鬼仙
小专栏:小专栏 - 苜蓿鬼仙
掘金:掘金 - 苜蓿鬼仙
微博:微博 - 苜蓿鬼仙
公众号:微信 - 苜蓿小站
小程序:微信 - 苜蓿小站
文档信息
- 本文作者:苜蓿鬼仙
- 本文链接:https://jijiucheng.github.io/2024/10/29/%E5%89%8D%E7%AB%AF-XSS%E5%AE%89%E5%85%A8%E9%97%AE%E9%A2%98/
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)