你的浏览器无法正常显示内容,请更换或升级浏览器!

Node.js 文件上传处理实战与安全加固

tenfei
tenfei
发布于2026-09-08 09:49 阅读9次
Node.js 文件上传处理实战与安全加固
讲解 Node.js 文件上传的完整实现与安全加固方案,涵盖 multer 配置、文件类型与大小限制、存储策略、病毒扫描思路、常见攻击防护等,附代码示例,避免上传功能成为服务器后门。
# Node.js 文件上传处理实战与安全加固 > 文件上传功能如果没有做好校验和防护,等于给攻击者开了一扇后门。本文从实现到安全加固,把上传功能一次做扎实。 ## 一、基础实现:multer multer 是 Express 生态最常用的上传中间件: ```js const multer = require("multer"); const path = require("path"); // 配置存储 const storage = multer.diskStorage({ destination: (req, file, cb) => cb(null, "uploads/"), filename: (req, file, cb) => { // 用随机名,别用原始文件名 const ext = path.extname(file.originalname); cb(null, Date.now() + "-" + Math.round(Math.random() * 1e9) + ext); } }); const upload = multer({ storage }); app.post("/api/upload", upload.single("file"), (req, res) => { res.json({ ok: true, file: req.file }); }); ``` > 第一步就埋下隐患:直接用原始文件名存储,可能被路径穿越或覆盖。 ## 二、文件类型校验 > ⚠️ 不能只信扩展名,Content-Type 也能伪造,要校验文件内容。 ```js const ALLOWED = [".jpg", ".png", ".gif", ".webp"]; const upload = multer({ storage, fileFilter: (req, file, cb) => { const ext = path.extname(file.originalname).toLowerCase(); if (!ALLOWED.includes(ext)) { return cb(new Error("仅支持图片格式")); } cb(null, true); } }); ``` ## 三、大小限制 不限制大小,服务器磁盘和带宽分分钟被打满: ```js const upload = multer({ storage, limits: { fileSize: 5 * 1024 * 1024 } // 5MB }); // 捕获超限错误 app.post("/api/upload", (req, res) => { upload.single("file")(req, res, (err) => { if (err) { if (err.code === "LIMIT_FILE_SIZE") { return res.status(413).json({ error: "文件不能超过 5MB" }); } return res.status(400).json({ error: err.message }); } res.json({ ok: true }); }); }); ``` ## 四、内容真实性校验 图片用魔数(Magic Number)校验文件头,防伪装: ```js // 读取文件头判断真实类型 const fs = require("fs"); function sniffImageType(filePath) { const buf = fs.readFileSync(filePath).subarray(0, 4); if (buf[0] === 0xFF && buf[1] === 0xD8) return "jpg"; if (buf.toString("ascii", 1, 4) === "PNG") return "png"; return null; } ``` > 也可以直接用 file-type 等库识别真实 MIME。 ## 五、存储安全策略 - 上传目录禁止执行脚本:Nginx 配置去掉 php/node 执行权限 - 文件名随机化,杜绝路径穿越 - 按日期分子目录存储,避免单目录文件过多 - 敏感文件不落盘,直接存对象存储 ## 六、常见攻击与防护 ### 1. 恶意脚本上传 攻击者上传 .php/.js 木马,配合服务器解析漏洞执行。 ```bash # Nginx 禁止上传目录执行脚本 location ^~ /uploads/ { default_type application/octet-stream; location ~* .(php|asp|jsp)$ { return 403; } } ``` ### 2. 文件名路径穿越 原始文件名含 ../../ 覆盖服务器文件。解决:随机化文件名,丢弃原始路径。 ### 3. 超大文件与并发打满带宽 限制大小 + 上传限速 + CDN 前置,Nginx 层限制请求体: ```bash # Nginx 限制请求体 10MB client_max_body_size 10m; ``` ### 4. 病毒木马 图片类内容过一遍杀毒扫描,或上传到云服务用安全检测能力。 ## 七、头像上传完整示例 ```js // 组合:类型 + 大小 + 随机名 const avatarUpload = multer({ storage: avatarStorage, limits: { fileSize: 2 * 1024 * 1024 }, fileFilter: (req, file, cb) => { const ext = path.extname(file.originalname).toLowerCase(); if (![".jpg", ".png", ".webp"].includes(ext)) { return cb(new Error("头像仅支持 jpg/png/webp")); } cb(null, true); } }); app.post("/api/user/avatar", avatarUpload.single("avatar"), async (req, res) => { if (!req.file) return res.status(400).json({ error: "请选择文件" }); // 读文件头校验真实图片类型 const realType = sniffImageType(req.file.path); if (!realType) { fs.unlinkSync(req.file.path); return res.status(400).json({ error: "文件不是有效图片" }); } res.json({ ok: true, url: "/uploads/" + req.file.filename }); }); ``` ## 八、检查清单 - [ ] 文件类型白名单 + 魔数校验 - [ ] 文件大小限制(应用层 + Nginx 层) - [ ] 文件名随机化存储 - [ ] 上传目录禁止脚本执行 - [ ] 目录按日期分片 - [ ] 日志记录上传来源 上传功能按这个清单加固,能挡住绝大多数攻击。

1

0

文章点评
Copyright © from 2021 by namoer.com
458815@qq.com QQ:458815
蜀ICP备2022020274号-2