You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何规避上传文件名引发的XSS漏洞?

如何防范文件名引发的XSS漏洞

嘿,这个场景太典型了——当用户上传的可控文件名直接被渲染到页面DOM中时,很容易触发存储型XSS。我来从前端JavaScript和服务器端两个层面给你具体的防护方案:

前端JavaScript防护方案

核心思路是永远不要把未转义的用户可控内容直接插入到HTML结构中,以下是几种可靠的实现方式:

  • 使用HTML转义函数处理文件名
    把文件名中的特殊HTML字符(<, >, ", ', &)转成对应的HTML实体,这样浏览器会把它们当成纯文本解析,而不是执行代码。比如写一个通用的转义函数:

    function escapeHtml(unsafeStr) {
        return unsafeStr
             .replace(/&/g, "&amp;")
             .replace(/</g, "&lt;")
             .replace(/>/g, "&gt;")
             .replace(/"/g, "&quot;")
             .replace(/'/g, "&#039;");
    }
    
    // 使用示例:展示文件名时先转义
    const maliciousFileName = "<img src=x onerror=alert(document.cookie)>";
    const safeFileName = escapeHtml(maliciousFileName);
    document.getElementById("file-name-container").innerHTML = safeFileName;
    
  • 用textContent替代innerHTML
    如果你只是要展示文件名文本,直接使用DOM元素的textContent属性,它会自动把内容当成纯文本处理,完全避免HTML解析:

    const fileName = "<img src=x onerror=alert(document.cookie)>";
    document.getElementById("file-name-container").textContent = fileName;
    
  • 创建文本节点插入DOM
    另一种更底层的方式是用document.createTextNode()生成纯文本节点,再添加到页面中:

    const fileName = "<img src=x onerror=alert(document.cookie)>";
    const textNode = document.createTextNode(fileName);
    document.getElementById("file-name-container").appendChild(textNode);
    

服务器端防护方案

前端防护是最后一道防线,服务器端防护才是根本,从源头切断恶意内容的传播:

  • 上传时重命名文件
    不要保留用户上传的原始文件名,而是生成一个安全的随机文件名(比如UUID+文件扩展名),把原始文件名存在数据库中用于展示。这样即使原始文件名有恶意代码,也不会被渲染到页面上。举个Node.js的例子:

    const fs = require('fs');
    const path = require('path');
    const { v4: uuidv4 } = require('uuid');
    
    // 处理文件上传逻辑
    const uploadDir = './uploads';
    const originalFileName = req.file.originalname;
    // 生成安全文件名:UUID+原文件扩展名
    const safeFileName = `${uuidv4()}${path.extname(originalFileName)}`;
    // 重命名上传的文件
    fs.renameSync(req.file.path, path.join(uploadDir, safeFileName));
    // 将safeFileName和originalFileName关联存入数据库
    db.query('INSERT INTO files (safe_name, original_name) VALUES (?, ?)', [safeFileName, originalFileName]);
    
  • 过滤/清理原始文件名
    如果必须保留原始文件名展示,可以在服务器端先对文件名进行清理:移除所有HTML特殊字符,或者限制文件名只能包含字母、数字和-_.这类安全符号。比如Python中的处理:

    import re
    
    def sanitize_filename(filename):
        # 只保留字母、数字和安全符号,移除其他字符
        return re.sub(r'[^\w\-.]', '', filename)
    
    malicious_filename = "<img src=x onerror=alert(document.cookie)>"
    safe_filename = sanitize_filename(malicious_filename)
    # safe_filename 会变成 "imgsrcxonerroralertdocumentcookie"
    
  • 输出文件名时做HTML转义
    即使前端已经做了转义,服务器端在返回文件名(比如通过接口返回给前端)时,也可以提前做HTML转义,实现双重防护。比如在Java中使用org.apache.commons.text.StringEscapeUtils.escapeHtml4()方法。

内容的提问来源于stack exchange,提问作者gstackoverflow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:45:26