Skip to content

Commit 4ec5112

Browse files
authored
fix: Markdown editor xss attack (#4556)
1 parent dfbf5aa commit 4ec5112

File tree

3 files changed

+48
-19
lines changed

3 files changed

+48
-19
lines changed

ui/src/components/markdown/MdEditor.vue

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<MdEditor :language="language" noIconfont noPrettier v-bind="$attrs" :sanitize="sanitize">
2+
<MdEditor :language="language" noIconfont noPrettier v-bind="$attrs">
33
<template #defFooters>
44
<slot name="defFooters"> </slot>
55
</template>
@@ -13,7 +13,6 @@ import { getBrowserLang } from '@/locales/index'
1313
import './assets/markdown-iconfont.js'
1414
// 引入公共库中的语言配置
1515
import ZH_TW from '@vavt/cm-extension/dist/locale/zh-TW'
16-
import sanitizeHtml from 'sanitize-html'
1716
defineOptions({ name: 'MdEditor' })
1817
const language = computed(() => localStorage.getItem('MaxKB-locale') || getBrowserLang() || '')
1918
config({
@@ -23,7 +22,4 @@ config({
2322
},
2423
},
2524
})
26-
const sanitize = (html: any) => {
27-
return sanitizeHtml(html)
28-
}
2925
</script>

ui/src/components/markdown/MdPreview.vue

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
11
<template>
2-
<MdPreview
3-
:language="language"
4-
noIconfont
5-
noPrettier
6-
:sanitize="sanitize"
7-
:codeFoldable="false"
8-
v-bind="$attrs"
9-
/>
2+
<MdPreview :language="language" noIconfont noPrettier :codeFoldable="false" v-bind="$attrs" />
103
</template>
114

125
<script setup lang="ts">
@@ -16,7 +9,6 @@ import { getBrowserLang } from '@/locales/index'
169
import useStore from '@/stores'
1710
// 引入公共库中的语言配置
1811
import ZH_TW from '@vavt/cm-extension/dist/locale/zh-TW'
19-
import sanitizeHtml from 'sanitize-html'
2012
defineOptions({ name: 'MdPreview' })
2113
2214
const emit = defineEmits(['clickPreview'])
@@ -30,9 +22,6 @@ config({
3022
},
3123
},
3224
})
33-
const sanitize = (html: any) => {
34-
return sanitizeHtml(html)
35-
}
3625
</script>
3726

3827
<style lang="scss" scoped>

ui/src/main.ts

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import router from '@/router'
1111
import i18n from '@/locales'
1212
import Components from '@/components'
1313
import directives from '@/directives'
14-
15-
import { config } from 'md-editor-v3'
14+
import { getDefaultWhiteList } from 'xss'
15+
import { config, XSSPlugin } from 'md-editor-v3'
1616
import screenfull from 'screenfull'
1717

1818
import katex from 'katex'
@@ -44,6 +44,50 @@ config({
4444
instance: mermaid,
4545
},
4646
},
47+
markdownItPlugins(plugins) {
48+
return [
49+
...plugins,
50+
{
51+
type: 'xss',
52+
plugin: XSSPlugin,
53+
options: {
54+
xss() {
55+
return {
56+
whiteList: Object.assign({}, getDefaultWhiteList(), {
57+
video: ['src', 'controls', 'width', 'height', 'preload', 'playsinline'],
58+
source: ['src', 'type'],
59+
input: ['class', 'disabled', 'type', 'checked'],
60+
iframe: [
61+
'class',
62+
'width',
63+
'height',
64+
'src',
65+
'title',
66+
'border',
67+
'frameborder',
68+
'framespacing',
69+
'allow',
70+
'allowfullscreen',
71+
],
72+
}),
73+
onTagAttr: (tag: string, name: any, value: any) => {
74+
if (tag === 'video') {
75+
// 禁止自动播放
76+
if (name === 'autoplay') return ''
77+
78+
// 限制 preload
79+
if (name === 'preload' && !['none', 'metadata'].includes(value)) {
80+
return 'preload="metadata"'
81+
}
82+
}
83+
return undefined
84+
},
85+
}
86+
},
87+
},
88+
},
89+
]
90+
},
4791
})
4892
const app = createApp(App)
4993
app.use(createPinia())

0 commit comments

Comments
 (0)