跳转到主内容
极星编程网:以代码为星,赴技术山海!

如何防止MongoDB GridFS被恶意刷入大量无用文件

GridFS上传必须校验元信息、使用GridFSBucket、绑定身份配额、预读校验大小、定期清理孤儿块;filename限255字符且禁路径遍历符,contentType须白名单,metadata需防深层嵌套与非法键名。 GridFS 上传前必须校验文件元信息 不校验
filename
、
contentType
和
metadata
,攻击者就能用随机字符串或超长路径名反复写入,撑爆
fs.files
集合。MongoDB 本身不限制文件名长度或格式,但业务侧必须拦住明显异常的值。
filename
应限制在 255 字符内,且禁止
/
、
../
、控制字符、Unicode 零宽空格等路径遍历或混淆符号
contentType
必须白名单校验,例如只允许
"image/jpeg"
、
"application/pdf"
等已知合法类型,不能只靠客户端传入的值
metadata
字段若开放写入,需递归检查嵌套层级(避免深度 > 5)和键名(禁止
$
开头或
.
出现在键中) 用 GridFSBucket 而非原始 collection 操作 直接往
fs.files
和
fs.chunks
插文档等于绕过所有安全钩子,连基本的 chunk 大小校验都失效。官方
GridFSBucket
类封装了原子写入、分块校验和自动 cleanup,是唯一可控入口。 永远不要用
db.fs.files.insertOne()
手动插入元数据文档 上传必须走
bucket.uploadFromStream()
,并设置
chunkSizeBytes
(建议 256KB,太小增加 chunk 数量,太大拖慢单次写入) 启用
disableMD5
(默认 true),避免 MD5 计算成为 DoS 攻击面 上传接口必须绑定身份与配额 GridFS 本身无权限模型,全靠上层服务控制。一个未鉴权或弱鉴权的上传端点,几行脚本就能打满磁盘。 每个上传请求必须关联明确用户 ID 或 API Key,并在 DB 中维护该主体的
daily_upload_count
和
total_size_bytes
上传前查 Redis 缓存做秒级限流(如
INCR user:123:upload:20240520
+
EXPIRE
),比查 MongoDB 快一个数量级 文件大小必须在内存中预读前 1MB 校验(不是只看
Content-Length
header,它可被伪造),超过阈值(如 100MB)直接 413 定期清理 orphaned chunks 是硬性运维动作 上传中断、客户端崩溃或代码 bug 都会导致
fs.chunks
里残留没有对应
fs.files
文档的块——这些“孤儿块”不会被自动回收,积少成多直接吃光磁盘空间。 每周跑一次
db.runCommand({ cleanUpOrphaned: "fs.chunks" })
(MongoDB 4.2+) 低版本需手写脚本:查出
fs.chunks.files_id
不在
fs.files._id
中的所有 chunk,再批量删除 清理前务必备份,命令执行期间会阻塞写入,安排在业务低峰期 最麻烦的不是配置,而是把「上传校验」和「配额扣减」做成原子操作——很多人用两个独立 DB 请求实现,中间失败就会导致配额没扣但文件已存,或者反之。这得靠事务或 Lua 脚本兜底,别图省事跳过去。

相关文章