InlineAttachment上传安全必修课:MIME白名单、文件名注入防御与5个常见陷阱
【免费下载链接】InlineAttachmentEasily paste and upload files/images in plain textareas项目地址: https://gitcode.com/gh_mirrors/in/InlineAttachment
InlineAttachment 是一个轻量的 JavaScript 文件上传插件,让用户把图片或文件直接拖拽、粘贴进纯文本 textarea(以及 CodeMirror 编辑器)中即可自动上传。但"拖拽即上传"的便捷背后藏着不少安全隐患。本文基于项目源码,带你快速掌握 MIME 白名单配置、文件名注入防御两条核心防线,并绕开 5 个高频踩坑点。🛡️
两条核心安全防线:动手配置前先懂原理
防线一:客户端 MIME 白名单(allowedTypes)
InlineAttachment 的默认配置内置了一个 MIME 白名单,定义在src/inline-attachment.js的inlineAttachment.defaults中:
allowedTypes: ['image/jpeg', 'image/png', 'image/jpg', 'image/gif']上传前的过滤逻辑在isFileAllowed()方法中,它做两件事:
- 过滤
file.kind === 'string'的条目(粘贴事件里混入的纯文本); - 将
file.type与白名单逐一比对,不在名单内的文件直接忽略,走浏览器默认行为。
完整配置项说明可参考docs/pages/configuration.rst。
⚠️关键认知:客户端白名单只是"体验优化",过滤发生在用户浏览器里,攻击者完全可以直接构造 HTTP 请求绕过它。真正的安全边界必须在服务端。
防线二:文件名注入防御(remoteFilename 重命名)
原始文件名是不可信输入:可能包含../路径穿越、空格、Unicode 特殊字符,甚至不同平台间的命名差异。
src/inline-attachment.js的uploadFile()处理得很克制——不直接采用原始文件名,只提取扩展名,然后生成新名字:
var remoteFilename = "image-" + Date.now() + "." + extension;服务端演示代码demo/upload_attachment.php又做了一层保险:用uniqid()重新生成文件名后再move_uploaded_file()落盘,客户端传来的名字彻底不被信任。前后端双重重命名,是文件名注入防御的正确姿势。✅
5个常见陷阱:90% 的开发者至少踩过一个
陷阱1:把客户端 MIME 白名单当安全边界
uploadUrl默认指向upload_attachment.php,而上传就是一个普通 POST 请求。攻击者无需打开你的页面,直接用 curl 就能向该接口提交任意文件。只做前端allowedTypes过滤,等于安全为零。服务端必须二次校验 MIME 类型,更可靠的是校验文件头(如 PHP 的getimagesize()),而不是只看$_FILES里的类型字段。
陷阱2:直接拿原始文件名存盘
若服务端用$file['name']拼接保存路径,../../之类的路径穿越可能让文件写出上传目录。正确做法就是项目演示的做法:服务端用uniqid()之类重新命名。
陷阱3:只过滤 MIME,不校验扩展名
仔细读demo/upload_attachment.php会发现一个隐患:
$filename = uniqid() . '.' . (pathinfo($file['name'], PATHINFO_EXTENSION) ?: 'png');扩展名直接取自用户上传的文件名,没有任何白名单校验。若能构造绕过 MIME 检查的.php文件,Web Shell 就直接落地了。扩展名要用白名单(jpg、png、gif),千万不要用黑名单。
陷阱4:用 '*' 关掉白名单
isFileAllowed()中有这样一句判断:allowedTypes.indexOf('*') === 0。也就是说,只要把'*'放在allowedTypes数组第一位,所有文件类型都会通过检查。这个"通配"能力方便调试,但上线前务必删掉,防止误配置导致全站文件裸奔。
陷阱5:上传目录在 Web 根目录内且可执行脚本
演示代码把文件存入 Web 可访问的data/目录。一旦上述任何一道防线被绕过,落在该目录的脚本就可能被执行。稳妥的做法:上传目录移出 Web 根目录、用反向代理/网关单独托管静态资源,或在目录内禁用脚本解析(Nginx/PHP 层禁止执行)。
30秒自查清单:对照检查你的上传接口
| 检查项 | 前端 | 服务端 |
|---|---|---|
| MIME 类型 | allowedTypes限定到具体类型,且'*'不在首位 | 二次校验 MIME / 文件头 |
| 文件名 | 自动重命名为image-时间戳.扩展名 | 再次重命名,永不用原始名 |
| 扩展名 | — | 白名单校验(jpg/png/gif) |
| 文件内容 | — | 校验文件头魔数,而非仅看类型字段 |
| 目录权限 | — | 上传目录禁执行或移出 Web 根目录 |
总结
InlineAttachment 在源码层面已经给出了很好的安全基线:客户端 MIME 白名单 + 前后端双重文件名重命名。但请记住:前端的每一道过滤都可能是装饰,安全必须由服务端闭环。对照上面的自查清单逐项落实,你的拖拽粘贴上传体验既能像 GitHub 一样顺滑,也能扛住真实的攻击。🔒
【免费下载链接】InlineAttachmentEasily paste and upload files/images in plain textareas项目地址: https://gitcode.com/gh_mirrors/in/InlineAttachment
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考