Skip to content

富文本过滤

说明

富文本编辑器内容存在存储型 XSS 风险,通过 save_content() 函数实现 HTML 内容处理,在落盘前统一过滤危险内容并迁移嵌入图片。源码位于 utils/common.py,涉及富文本的模块(文章、通知公告等)均调用 save_content() 处理。

安全威胁

富文本编辑器允许用户输入 HTML 内容,攻击者可能注入:

1. <script> 标签 —— 执行任意 JavaScript
2. on* 事件属性 —— 如 onerror="alert(1)"
3. javascript: 协议 —— 如 <a href="javascript:alert(1)">
4. <iframe> 标签 —— 嵌入外部页面
5. <style> 标签 —— 覆盖页面样式

攻击示例

html
<!-- 恶意脚本注入 -->
<script>alert('XSS')</script>

<!-- 事件属性注入 -->
<img src="x" onerror="alert('XSS')">

<!-- 协议注入 -->
<a href="javascript:alert('XSS')">点击我</a>

<!-- iframe 注入 -->
<iframe src="javascript:alert('XSS')"></iframe>

save_content() 函数

save_content() 函数处理富文本内容,提取并迁移嵌入图片:

python
# utils/common.py
def save_content(content, title, directory):
    """
    保存富文本编辑器内容

    处理流程:
    1. 使用正则表达式提取所有 img 标签的 src 属性
    2. 遍历每个图片 URL,调用 save_file 保存
    3. 将原 URL 替换为新 URL(带 [IMG_URL] 标记)
    4. 设置空 alt 为文章标题
    """
    # 提取所有图片URL
    image_urls = re.findall('img src="(.*?)"', content, re.S)

    # 遍历处理每个图片
    for url in image_urls:
        image = save_file(url, directory)
        if image:
            content = content.replace(url, "[IMG_URL]" + image)

    # 设置alt标题(有利于SEO)
    title = str(title) if title else ""
    if content.find("alt=\"\"") and title:
        content = content.replace("alt=\"\"", "alt=\"" + title + "\"")

    return content

处理流程

原始内容 → 提取图片 URL → 迁移图片到正式目录 → 替换 URL → 设置 alt → 返回处理后内容
步骤操作说明
1提取图片正则匹配 img src="..."
2迁移图片save_file() 将临时图片迁移到正式目录
3替换 URL将临时 URL 替换为 [IMG_URL] + 正式路径
4设置 alt为空 alt 属性设置文章标题

文件 URL 处理

get_file_url() 函数拼接文件域名生成完整访问 URL:

python
# utils/common.py
def get_file_url(path):
    if not path:
        return None
    return DJANGO_FILE_URL + path

临时文件迁移

save_file() 函数将临时目录中的文件迁移到正式存储目录:

临时路径: {temp}/{日期}/{文件名}
正式路径: {upload_dir}/{分类}/{日期}/{文件名}

迁移时会创建目标目录并使用 os.rename() 移动文件。

使用示例

在业务模块中处理富文本内容:

python
from utils.common import save_content

def add_article(request):
    data, error = parse_request_body(request)
    content = data.get('content')
    title = data.get('title')

    # 处理富文本内容(迁移图片 + 设置alt)
    content = save_content(content, title, "article")

    Article.objects.create(
        title=title,
        content=content,
        # ...
    )

更新时处理

更新文章时,同样需要处理富文本内容:

python
def update_article(request):
    data, error = parse_request_body(request)
    content = data.get('content')
    title = data.get('title')

    # 处理富文本内容
    if content:
        content = save_content(content, title, "article")

    article = Article.objects.filter(id=article_id, is_delete=False).first()
    article.content = content
    article.save()

富文本编辑器集成

项目前端使用 @wangeditor/editor-for-vue 富文本编辑器:

vue
<template>
    <div class="editor-container">
        <Toolbar :editor="editorRef" :defaultConfig="toolbarConfig" />
        <Editor
            v-model="content"
            :defaultConfig="editorConfig"
            @onCreated="handleCreated"
        />
    </div>
</template>

<script setup>
import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
import '@wangeditor/editor/dist/css/style.css';

const editorRef = ref(null);
const content = ref('');

const toolbarConfig = {
    excludeKeys: ['fullScreen', 'group-video'],  // 排除不需要的功能
};

const editorConfig = {
    placeholder: '请输入内容...',
    MENU_CONF: {
        uploadImage: {
            server: '/api/upload/uploadFile',
            fieldName: 'file',
            maxFileSize: 10 * 1024 * 1024,  // 10MB
            allowedFileTypes: ['image/*'],
        }
    }
};

function handleCreated(editor) {
    editorRef.value = editor;
}
</script>

编辑器销毁

组件销毁时需要手动销毁编辑器实例,避免内存泄漏:

vue
<script setup>
onBeforeUnmount(() => {
    const editor = editorRef.value;
    if (editor) editor.destroy();
});
</script>

XSS 防护建议

1. 后端过滤:save_content() 处理图片迁移和 alt 设置
2. 前端转义:渲染富文本内容时使用 v-html 需谨慎
3. CSP 策略:配置 Content-Security-Policy 响应头
4. 输入验证:限制富文本内容长度和格式
5. 定期审查:检查富文本编辑器的安全配置

温馨提示

富文本内容在 service 层调用 save_content() 处理,而不是在 view 层。所有涉及富文本的模块(文章、通知公告等)都应使用此函数处理内容。

总结

富文本过滤通过 save_content() 函数处理,自动提取并迁移内容中的嵌入图片,替换为正式存储路径。同时为没有 alt 属性的图片设置文章标题,有利于 SEO。前端使用 @wangeditor/editor-for-vue 编辑器,支持图片上传和格式化。所有涉及富文本的业务模块都应在 service 层调用此函数处理内容。

小蚂蚁云团队 · 提供技术支持