一、问题描述
可能都知道使用v-html
插入富文本,存在安全隐患,比如 cross-site scripting attack(xss)
。但具体什么情况下v-html
会引发安全问题呢?是否内容中含有<scrpit>
标签就会触发执行脚本呢?
二、问题探究
写个简单的代码来看看:
<template><div v-html="content" />
</template>
<script setup lang="ts">
const content = `<script>alert('XSS Attack')<\/script>`
</script>
可以看到script
节点成功的插入文档,但页面并没有出现相应的弹框。通过文档可以看到v-html是通过修改innerHtml来实现的,当然也可以从源码里看到:
那么换成innerHTML
的方式动态插入试试:
在chrome DevTools中的元素面板下选中目标节点,在控制台中输入:
const name = "<script>alert('XSS Attack')</script>";
$0.innerHTML = name;
可以发现依然没有任何作用,那是因为在HTML标准中规定使用innerHtml插入script标签时不会执行里面的任何代码:
Although this may look like a cross-site scripting attack, the result is harmless. HTML specifies that a <script> tag inserted with innerHTML
should not execute
.
但这并不代表这种动态插入的方式没有安全问题:
<template><div v-html="content" />
</template>
<script setup lang="ts">
const content = `<img src=x οnerrοr="alert('XSS Attack')">`
</script>
可以看到终于出现了:
三、解决方案
为了避免v-html
潜在的安全隐患,可以使用dompurify
(先安装dompurify):
DOMPurify
sanitizes HTML and prevents XSS attacks. You can feed DOMPurify with string full of dirty HTML and it will return a string (unless configured otherwise) with clean HTML. DOMPurify will strip out everything that contains dangerous HTML and thereby prevent XSS attacks and other nastiness. It’s also damn bloody fast. We use the technologies the browser provides and turn them into an XSS filter. The faster your browser, the faster DOMPurify will be.
使用方法:
<template><div v-html="content" />
</template>
<script setup lang="ts">
import DOMPurify from 'dompurify';
const content = DOMPurify.sanitize(`<img src=x οnerrοr="alert('XSS Attack')">`)
</script>