VP导航 VP导航
首页 提交网址

资讯文章 资讯 · NEWS

用户上传的图片和附件:目录站那道不能省的服务端校验

2026-10-23 约 2,130 字 预计阅读 5 分钟 yiyunkj

用户上传的图片和附件:目录站那道不能省的服务端校验 用

开放收录的目录站,提交表单里基本都有一项「上传站点 Logo」或者「上传截图」。功能很小,出事的量级不小。

我见过最离谱的一次,是有人上传了一个 .jpg,后台照单全收存进了上传目录,然后那个目录恰好允许解析 PHP——文件名是 logo.jpg.php,前台的扩展名校验被双扩展名绕过去了。

用户上传文件的服务端校验流程示意图

图片来源:网络,版权归原作者所有,侵权请联系删除

前端校验不算校验

先把这件事说清楚:在 JS 里判断文件类型、限制大小,属于用户体验优化,不属于安全控制。攻击者用 curl 或者 Postman 直接打你的接口,一行前端代码都不会执行。

所有校验必须在服务端再来一遍。OWASP 的文件上传清单里第一条就是这个意思:客户端验证可以被绕过,服务端必须自己验。

服务端要验的五样东西

一、扩展名白名单,不是黑名单

定一个明确的允许列表,比如只要 jpg、png、webp。别去列举「禁止 php、jsp、asp」,你列举不完。同样功能的扩展名在不同服务器配置下有一堆变体:phtml、php5、pht、jspx,靠黑名单永远漏。

校验要在文件名解码之后做,而且要挡掉这几类绕过:

  • 双扩展名:logo.jpg.php
  • 空字节截断:logo.php%00.jpg
  • 大小写变形:logo.pHp
  • Windows NTFS 备用数据流:logo.php::$DATA,简单起见只要文件名里出现冒号就拒

二、内容类型看魔数,不看 Content-Type

请求头里的 Content-Type 是客户端自己填的,想填什么填什么。真正可靠的是读文件开头几个字节:

类型文件头(十六进制)
JPEGFF D8 FF
PNG89 50 4E 47
GIF47 49 46 38
PDF25 50 44 46
ZIP(含 docx、xlsx)50 4B 03 04

读到的类型和声明的不一致,直接拒。这一条顺带挡掉了「把 PHP 文件前面拼一段 PNG 头」这种混血文件。

三、重新编码一遍图片

这一步很多人省了,其实很值。用图像处理库把上传的图重新解码再编码一次(顺便缩放、压缩),藏在 EXIF 里的脚本、注释段里的 payload 会被一起丢掉。这是「重编码」区别于「只校验」的地方——你不只是在判断它是不是一张图,你是在重新生成一张干净的图。

顺带解决另一件事:EXIF 里的 GPS 坐标。用户上传的截图常常带着拍摄位置,你把它原样存下来再公开出去,属于把别人的信息泄露出去。重编码默认就剥掉了。

四、文件名由服务端生成

永远不要用用户给的文件名当存储路径。生成一个 UUID 或者哈希,扩展名按检测出来的真实类型重新拼。原来的文件名只留在数据库里当显示用。

这一条同时挡掉了路径穿越(../../etc/passwd)、覆盖已有文件、以及用奇怪文件名打乱过滤规则的几种玩法。

五、大小限制要设在最外层

nginx 的 client_max_body_size 先卡一道,应用框架再卡一道,业务代码最后卡一道。只在应用代码里判断大小的问题是:nginx 可能已经把几百兆的请求体读进内存或临时文件了,应用层才说不要。限制要设在缓冲之前。

SVG 单独拎出来讲

SVG 是 XML,能带 <script>,能在浏览器里执行。用户传一个 SVG,你在前台用 <img> 标签显示它,脚本不会执行;但只要有任何一个地方把它当文档加载(直接访问那个 URL、放进 iframe、某些预览功能),就是一个存储型 XSS。

三种处理办法,按推荐程度排:

  1. 不接受 SVG。目录站的 Logo 场景,PNG 和 WebP 完全够用。
  2. 必须接受的话,过一遍 XML 清洗,去掉 script、事件属性、外部实体引用,同时关掉解析器的外部实体解析(XXE 也是从这进来的)。
  3. 存可以,但只在独立的、无 Cookie 的域名上提供,并且强制 Content-Disposition: attachment。

第 3 条的原理是:就算 SVG 里真有脚本被执行了,它在独立域上,读不到主站的会话 Cookie。这是隔离思路,不是清洗思路,两者可以叠加。

文件该存在哪儿

优先级从高到低:

  • 独立的对象存储(S3、OSS、COS),私有读写,通过签名 URL 或者 CDN 提供
  • 独立的无 Cookie 域名,物理上和主站分开
  • webroot 之外,通过一个 handler 按 ID 映射(someid → file.ext),不要让用户能猜到真实路径

最后一条要强调:不要放在能解析脚本的目录里。上传目录如果配了 PHP 解析,前面所有的校验都是在给攻击者出附加题,他只要把可执行文件放进去就够了。上传目录应该禁止执行任何脚本,并且配 X-Content-Type-Options: nosniff,别让浏览器自己猜类型。

还有两件容易漏的

防 CSRF。上传接口必须带 CSRF token,否则攻击者可以在别的站点构造一个表单,让已登录的管理员在不知情的情况下上传文件。

限速和配额。单个用户每分钟能传几个、总共能占多大空间,要有上限。不然你遇到的不是攻击,是有人拿你的站当图床,磁盘三个月就满了。


落到目录站的具体配置

开放提交的表单里,Logo 和截图是必填还是选填?我倾向于选填,而且提交后进入人工审核队列再展示。审核队列本身也能挡掉大部分批量上传的垃圾。

另外,上传后的图如果要对外展示,记得给它配好宽高属性和 alt 文本。这既是安全之外的事,也是图片搜索那一路流量的入口——顺手就做了。

本文标签 文件上传安全校验 SVG与EXIF处理 目录站用户提交防护
← 上一篇 按 IP 自动跳转地区版本:目录站的地理重定向把爬虫 下一篇 → 被人工处置之后:目录站的申诉信该怎么写,才不会被第二

— 本文完 —

提交网址

发现好站,欢迎自荐收录

站内搜索

站点统计

  • 今日审核0
  • 已收录站点3744
  • 正常访问3737
  • 失联站点7
  • 累计访问175

网站分类

  • AI工具 0
    AI对话0 AI绘画0 AI写作0 AI编程0 AI音视频0 AI办公效率0
  • 开发编程 0
    前端开发0 后端开发0 移动开发0 开源与代码托管0 数据库0 开发文档与教程0
  • 设计素材 0
    UI设计0 图标素材0 免费图库0 字体下载0 配色工具0 设计模板0
  • 站长工具 0
    网站统计0 SEO工具0 域名与主机0 收录提交0 建站程序0 运维监控0
  • 学习教育 0
    编程教程0 语言学习0 职业技能0 公开课与慕课0 考试题库0 中小学教育0
  • 生活服务 0
    交通出行0 外卖点餐0 房产租房0 医疗健康0 政务办事0 快递物流0
  • 影音娱乐 0
    影视观看0 音乐音频0 游戏资源0 短视频直播0 小说阅读0
  • 电商购物 0
    综合商城0 比价工具0 导购返利0 二手交易0 团购优惠0
  • 综合其他 1
    实用工具0 资源合集0 小众站点0 个人博客0 论坛社区0
  • 新闻资讯 0
    科技资讯8 财经媒体1 行业动态0 社会热点0 综合门户0
  • 资讯文章 300

最新收录

  • 快科技
  • 天极网
  • 太平洋科技
  • 比特网
  • 盛拓优讯IT168
  • 通义千问
  • Kimi
  • DeepSeek

浏览排行

  1. 满分作文网 6
  2. Let's Enhance 3
  3. 淘菜菜 3
  4. MasterClass 3
  5. TypeScript 中文网 3
  6. Zhengziying 3
  7. 得意生活 3
  8. 镇江网友之家 3

联系我们

bQ:12345678

电话:400-8888-888

邮箱:admin@example.com

时间:09:00-21:00

友情链接

车机屋·焊锡条·探兔AI导航·静电测试仪·大学生联盟

关于我们|广告合作|隐私条款|网站地图

原ICP备00000000号-1,@2026

由 Z-BlogPHP 驱动