如何在Nest.js中阻止public目录内的上传文件被执行?
如何阻止public文件夹中用户上传的可执行脚本被执行?
针对你允许用户上传任意类型文件到public目录的场景,要避免恶意脚本执行导致应用崩溃,可以从以下几个方面入手:
1. 禁止服务器解析执行上传的脚本文件
如果你的应用用Node.js(比如Express)提供静态文件服务,默认情况下express.static会根据文件后缀设置Content-Type,比如.js会被设为application/javascript,浏览器会执行它。你可以通过自定义响应头,强制将这类文件标记为纯文本:
app.use('/public', express.static('public', { setHeaders: (res, path) => { // 匹配常见脚本后缀 const scriptExtensions = /\.(js|mjs|ts|py|php)$/i; if (scriptExtensions.test(path)) { res.setHeader('Content-Type', 'text/plain'); } } }));
这样浏览器拿到脚本文件时会当作纯文本展示,而不会执行。
2. 重命名上传文件,剥离可执行后缀
不要保留用户上传的原始文件名和后缀,改用随机哈希值+非执行后缀命名。比如:
- 原始文件名:
malicious.js - 重命名后:
a1b2c3d4e5.upload
这样即使文件内容是脚本,因为后缀不属于可执行类型,服务器和浏览器都不会触发执行逻辑。代码示例:
const crypto = require('crypto'); function generateSafeFilename() { const hash = crypto.randomBytes(16).toString('hex'); // 统一用.upload后缀 return `${hash}.upload`; }
3. 把上传文件移到非Web可访问目录
不要把用户上传的文件放在public(Web根目录)下,而是新建一个独立的uploads目录(和public同级),然后通过后台接口来提供文件访问。比如在Express中写一个路由:
const fs = require('fs').promises; const path = require('path'); app.get('/uploads/:filename', async (req, res) => { const filename = req.params.filename; const filePath = path.join(__dirname, 'uploads', filename); try { const content = await fs.readFile(filePath); // 根据实际文件类型设置Content-Type,或默认设为text/plain res.setHeader('Content-Type', 'text/plain'); res.send(content); } catch (err) { res.status(404).send('File not found'); } });
这样用户无法直接通过URL访问上传文件,必须通过你的接口,你可以在接口里做更多安全校验。
4. 校验文件真实类型(不要只看后缀)
用户可能会把脚本文件改成.jpg后缀绕过检查,所以要基于文件内容判断真实类型。可以用file-type库:
const { fileTypeFromFile } = require('file-type'); async function checkFileType(filePath) { const fileType = await fileTypeFromFile(filePath); if (!fileType) { // 无法识别的类型,直接拒绝或标记为危险 return false; } // 允许的类型白名单,比如只允许图片、文档等 const allowedTypes = ['image/jpeg', 'image/png', 'application/pdf', 'text/plain']; return allowedTypes.includes(fileType.mime); }
如果检测到是脚本类型的文件,可以直接拒绝上传,或者转义内容后再存储。
5. 设置文件系统权限
在服务器上,给上传的文件设置严格的权限,禁止执行权限:
- Linux/macOS:执行
chmod 644 /path/to/public/uploads/*,只保留读写权限,去掉执行权限 - Windows:右键文件→属性→安全→设置所有用户的执行权限为拒绝
这样即使有人尝试在服务器端执行文件,也会因为权限不足失败。
内容的提问来源于stack exchange,提问作者codeForCoffee
相关产品推荐
相关产品推荐

