fix: Markdown editor xss attack

This commit is contained in:
shaohuzhang1 2025-12-24 11:31:59 +08:00
parent d8d15c8902
commit 1ffe5c1404
3 changed files with 48 additions and 19 deletions

View File

@ -1,5 +1,5 @@
<template>
<MdEditor :language="language" noIconfont noPrettier v-bind="$attrs" :sanitize="sanitize">
<MdEditor :language="language" noIconfont noPrettier v-bind="$attrs">
<template #defFooters>
<slot name="defFooters"> </slot>
</template>
@ -13,7 +13,6 @@ import { getBrowserLang } from '@/locales/index'
import './assets/markdown-iconfont.js'
//
import ZH_TW from '@vavt/cm-extension/dist/locale/zh-TW'
import sanitizeHtml from 'sanitize-html'
defineOptions({ name: 'MdEditor' })
const language = computed(() => localStorage.getItem('MaxKB-locale') || getBrowserLang() || '')
config({
@ -23,7 +22,4 @@ config({
},
},
})
const sanitize = (html: any) => {
return sanitizeHtml(html)
}
</script>

View File

@ -1,12 +1,5 @@
<template>
<MdPreview
:language="language"
noIconfont
noPrettier
:sanitize="sanitize"
:codeFoldable="false"
v-bind="$attrs"
/>
<MdPreview :language="language" noIconfont noPrettier :codeFoldable="false" v-bind="$attrs" />
</template>
<script setup lang="ts">
@ -16,7 +9,6 @@ import { getBrowserLang } from '@/locales/index'
import useStore from '@/stores'
//
import ZH_TW from '@vavt/cm-extension/dist/locale/zh-TW'
import sanitizeHtml from 'sanitize-html'
defineOptions({ name: 'MdPreview' })
const emit = defineEmits(['clickPreview'])
@ -30,9 +22,6 @@ config({
},
},
})
const sanitize = (html: any) => {
return sanitizeHtml(html)
}
</script>
<style lang="scss" scoped>

View File

@ -11,8 +11,8 @@ import router from '@/router'
import i18n from '@/locales'
import Components from '@/components'
import directives from '@/directives'
import { config } from 'md-editor-v3'
import { getDefaultWhiteList } from 'xss'
import { config, XSSPlugin } from 'md-editor-v3'
import screenfull from 'screenfull'
import katex from 'katex'
@ -44,6 +44,50 @@ config({
instance: mermaid,
},
},
markdownItPlugins(plugins) {
return [
...plugins,
{
type: 'xss',
plugin: XSSPlugin,
options: {
xss() {
return {
whiteList: Object.assign({}, getDefaultWhiteList(), {
video: ['src', 'controls', 'width', 'height', 'preload', 'playsinline'],
source: ['src', 'type'],
input: ['class', 'disabled', 'type', 'checked'],
iframe: [
'class',
'width',
'height',
'src',
'title',
'border',
'frameborder',
'framespacing',
'allow',
'allowfullscreen',
],
}),
onTagAttr: (tag: string, name: any, value: any) => {
if (tag === 'video') {
// 禁止自动播放
if (name === 'autoplay') return ''
// 限制 preload
if (name === 'preload' && !['none', 'metadata'].includes(value)) {
return 'preload="metadata"'
}
}
return undefined
},
}
},
},
},
]
},
})
const app = createApp(App)
app.use(createPinia())