简介:一套基于ASP(Active Server Pages)的图片上传管理源码,面向需要搭建个人相册、小型图库或为网站集成图片管理模块的开发者和站长。系统不仅具备图片批量上传、在线预览、列表异步加载,还包含用户登录、权限校验、图片下载等完整流程;后台与前台分离,适合直接部署或二次开发。压缩包共329个文件,其中57个asp构成主要逻辑,另有41个js处理前端交互、7个css控制样式,159个gif与39个png、15个jpg用于界面图标和图片素材,2个mdb保存系统数据,2个swf提供旧版Flash辅助功能,整体大小仅2.47MB,轻量易用。已有1010人学习使用,对掌握ASP基础、想了解传统Web开发中图片上传与后台管理实现方式的读者而言,这是一份可运行的参考案例。通过阅读UpLoad_Class上传类、Ajax图片列表、管理员列表等模块,可快速上手文件上传、异步刷新、会话验证等典型场景,并复用代码构建自己的图库或内容管理系统。
1. 图片上传管理源码 ASP:一个老技术栈,为什么还值得拆开看
接手一家公司的内网维护时,后台还跑着一套十年前用 ASP 写的图片上传管理模块。新系统排期排了一年多,老模块还得继续用,图片越积越多,偶尔有同事说“传不上去了”,我得先翻上传日志再查 IIS 配置。那段时间我把这类源码的套路翻了个底朝天:它们本质上就是一段跑在 IIS 上的 VBScript 脚本,负责接收图片、校验类型、改名落盘、记录索引、再提供一个能看能删的后台页面。对还在维护遗留 ASP 系统的开发者来说,这类源码不是“过时的代码垃圾”,而是一套仍然扛着业务在跑的基础设施。它适合两类人:一类是接手了老系统、必须看懂并修好上传模块的从业者;另一类是想在轻量 Windows 主机上快速搭一个图片管理后台,又不想引入整套新框架的务实派。这篇不评价哪个下载包好用,而是把“好用”背后的技术骨架拆开,让你能自己搭一个,也能判断网上源码靠不靠谱。
2. ASP 图片上传的技术原理:二进制流、FSO 与三种存储路线
2.1 为什么文件上传不能只靠 Request.Form:multipart 解析是怎么回事
普通表单提交时,浏览器把字段拼成key=value&key=value,ASP 用Request.Form("字段名")就能直接读到,但文件上传不是这套逻辑。只要<form>指定了enctype="multipart/form-data",浏览器就会把整个请求体按boundary分隔成多个片段,每个字段、每个文件各占一个part。文件内容以原始二进制形式夹在请求体里,Request.Form("picfile")拿去的是空字符串,真正的字节数据躺在Request.BinaryRead(Request.TotalBytes)里。这也是源码里总是先读Request.TotalBytes再取内容的根本原因。
一个完整的文件part长这样:先是分隔符--boundary,接着是Content-Disposition头,里面有表单字段名和原始文件名,然后是空行,空行之后才是文件的一串字节,最后以回车换行加下一个分隔符收尾。所以无组件上传的核心工作就两件事:用字节定位找到文件头的位置,再从头部解析出filename,最后把两个分隔符之间的字节原样写进磁盘。整个过程只允许用InStrB、MidB这类二进制函数操作,一旦把整段请求体用字符串转换函数转成文本,图片基本就废了,具体翻车现场放在第 5 章讲。
2.2 三种存储路线对比:别一上来就想着把图片塞进数据库
图片传上来之后放在哪里,直接决定这套源码的体量和管理复杂度。我维护过的 ASP 图片管理模块,存储路线基本就三种,各有利弊。用表格一眼能看清:
| 存储路线 | 图片本体位置 | 优点 | 缺点 | 适用规模 |
|---|---|---|---|---|
| 文件夹 + 数据库索引 | 磁盘目录(如 /uploads/2025/04/) | 图片由 IIS 直接服务,访问快;数据库只存路径和元数据,查询灵活 | 需要额外维护目录结构,备份时要同时备份文件夹和库 | 中小型后台,几千到几万张图都没问题 |
| 纯文件夹 | 磁盘目录,按日期/ID 分层 | 零数据库依赖,脚本轻,迁移简单 | 列表、搜索、删除都要扫描目录,功能约等于零 | 临时接收站、日志留档 |
| 二进制入库 | 数据库的 OLE 对象字段 | 文件跟着库走,单一备份 | 库体积膨胀极快,连接开销大,输出图片时还要Response.BinaryWrite,并发一高就卡 | 极少量图片,非必要不选 |
我一般选第一种:图片本质是静态资源,让 IIS 直接返回文件比走脚本输出快一个数量级;数据库里只存文件名、路径、大小、上传时间,列表页一次查询就能分页。这里给个容易被忽略的提醒:Access 库并发能力弱,图片超过几千张、上传频率一高,及时把库迁到 SQL Server Express 或改用 SQLite,老源码的连接字符串往往只改一行就能切换。
2.3 无组件上传类的选型边界:判断一套源码可不可信的三把尺子
网上流传的 ASP 上传管理源码,十有八九是基于某个“无组件上传类”改的,核心代码就二三百行,所谓“好用”其实看三点。第一,看它处理请求体时用的是不是MidB/InStrB这类二进制函数,如果看到BytesToStr转换成字符串再处理,直接放弃,保存出来的图多半打不开。第二,看它有没有把大小限制、扩展名列表留成可配置的变量,写死MaxSize = 1024的源码一抓一大把,改起来全是坑。第三,看它对客户端文件名的态度,成熟的源码通常不会信任浏览器传来的filename,要么截取安全后缀,要么干脆用服务端随机名。后面第 3 章给的最小实现,就是把这三把尺子具象化。
3. 零基础搭一个可用版本:表单、接收、落盘、入库
3.1 前端表单与上传入口
先写一个最朴素的传图页面,命名upload.html。这里的关键属性就一个:enctype="multipart/form-data",忘记写它,后端Request.TotalBytes拿到的就不是分片结构,整个上传逻辑直接失效。
<form method="post" enctype="multipart/form-data" action="upload.asp"> <input type="file" name="picfile" accept="image/*" /> <input type="text" name="remark" placeholder="备注信息" /> <button type="submit">上传</button> </form>accept="image/*"只是浏览器端的友好提示,不能当安全边界,后端的扩展名校验一步都不能省。action="upload.asp"指向接下来要写的处理脚本。文件字段名固定为picfile,后端解析时也要用同一个名字去匹配,改一个就得两头都改。
3.2 服务端接收与保存:核心代码
在站点根目录建upload.asp,核心处理逻辑按四步走:读请求体、定位文件数据区、用 ADODB.Stream 落盘、把元数据写进数据库。下面这段是完整可运行的最小版本,我在关键行做了注释。
<% ' ========== 配置区 ========== Dim MaxSize : MaxSize = 2 * 1024 * 1024 ' 大小上限:2MB Dim AllowExt : AllowExt = "jpg,jpeg,png,gif,webp" ' 允许的扩展名,逗号分隔 Dim SaveDir : SaveDir = Server.MapPath("/uploads/") ' 存放目录 Dim Conn : Set Conn = Server.CreateObject("ADODB.Connection") ' ========== 第一步:读取请求体 ========== Dim TotalBytes : TotalBytes = Request.TotalBytes If TotalBytes = 0 Then Response.Write "没有收到任何数据" Response.End End If If TotalBytes > MaxSize Then Response.Write "文件超过 " & MaxSize & " 字节限制" Response.End End If Dim bData : bData = Request.BinaryRead(TotalBytes) ' ========== 第二步:从 Content-Type 里取 boundary ========== Dim sContentType : sContentType = Request.ServerVariables("CONTENT_TYPE") Dim sBoundary : sBoundary = Mid(sContentType, InStr(sContentType, "boundary=") + 9) sBoundary = Replace(sBoundary, Chr(34), "") ' 去掉引号 sBoundary = Replace(sBoundary, vbCrLf, "") ' 去掉可能的回车换行 ' ========== 第三步:用字节定位文件数据区 ========== Dim bCrlf : bCrlf = StrToBytes(vbCrLf & vbCrLf) ' 头部与内容之间的空行 Dim iNamePos : iNamePos = InStrB(bData, StrToBytes("filename=""")) If iNamePos = 0 Then Response.Write "请求体中没有文件" Response.End End If ' 从 filename=" 往后截一段,用来解析原始文件名和 Content-Type Dim sHeader : sHeader = BytesToAscii(MidB(bData, iNamePos, 512)) ' 这里省去从 sHeader 里正则取 filename 的细节,重点是拿到客户端原始文件名 sFileName Dim iDataStart : iDataStart = InStrB(iNamePos, bData, bCrlf) iDataStart = iDataStart + LenB(bCrlf) ' 跳过头部空行,进入文件字节 Dim iDataEnd : iDataEnd = InStrB(iDataStart, bData, StrToBytes(vbCrLf & "--" & sBoundary)) ' 文件字节末尾会带一个回车换行,实际内容长度要减 2 Dim iFileLen : iFileLen = iDataEnd - iDataStart - 2 ' ========== 第四步:ADODB.Stream 落盘 ========== Dim fso : Set fso = Server.CreateObject("Scripting.FileSystemObject") If Not fso.FolderExists(SaveDir) Then fso.CreateFolder(SaveDir) End If Dim sNewName : sNewName = Year(Now()) & Month(Now()) & Day(Now()) & "_" & Hour(Now()) & Minute(Now()) & Second(Now()) & "_" & Int(Rnd() * 10000) & ".jpg" Dim oFile : Set oFile = Server.CreateObject("ADODB.Stream") oFile.Type = 1 ' 1 表示二进制 oFile.Open oFile.Write MidB(bData, iDataStart, iFileLen) oFile.SaveToFile SaveDir & "\" & sNewName, 2 ' 2 表示覆盖 oFile.Close Set oFile = Nothing Response.Write "保存成功:" & sNewName %>这段代码的逻辑说明分几层。Request.BinaryRead返回的是字节数据,MidB、InStrB是对字节做定位和切片的标准函数,全程没有把整段请求体转成字符串,所以存出来的文件不会损坏。iDataEnd - iDataStart - 2减掉的是文件内容末尾自带的回车换行,不少人在这里栽过跟头,不减会把两个多余的字节写进图片头部,导致图片无法识别。SaveDir用Server.MapPath把虚拟路径转成物理路径,这是 ASP 脚本落盘的固定套路。落盘时我没有保留原始文件名,而是用时间戳加随机数生成新文件名,这个习惯能规避掉后面讲的路径穿越和中文乱码一揽子问题。代码里用到的StrToBytes和BytesToAscii是辅助函数,常见做法是用 ADODB.Stream 做编码转换,第 5 章排错时再补。
3.3 元数据入库:Access 表结构与参数化写入
图片落盘后必须在数据库里留下索引,否则列表、删除、搜索全都无从谈起。Access 里建一张最简单的表,字段设计如下:
| 字段 | 类型 | 说明 |
|---|---|---|
| id | 自动编号 | 主键 |
| filename | 文本(255) | 服务端文件名 |
| savepath | 文本(255) | 相对路径,如 /uploads/xxx.jpg |
| filesize | 长整型 | 文件字节数 |
| ext | 文本(10) | 扩展名 |
| uploadtime | 日期/时间 | 上传时间 |
建表 SQL 可以直接在 Access 查询窗口里执行:CREATE TABLE pics (id AUTOINCREMENT PRIMARY KEY, filename TEXT(255), savepath TEXT(255), filesize LONG, ext TEXT(10), uploadtime DATETIME)。写入代码我用参数化,而不是拼 SQL 字符串,这是一个容易被新手忽略但能救命的好习惯。
Dim oCmd : Set oCmd = Server.CreateObject("ADODB.Command") oCmd.ActiveConnection = Conn oCmd.CommandText = "INSERT INTO pics (filename, savepath, filesize, ext, uploadtime) VALUES (?, ?, ?, ?, ?)" oCmd.Parameters.Append oCmd.CreateParameter("p1", 200, 1, 255, sNewName) oCmd.Parameters.Append oCmd.CreateParameter("p2", 200, 1, 255, "/uploads/" & sNewName) oCmd.Parameters.Append oCmd.CreateParameter("p3", 3, 1, , iFileLen) oCmd.Parameters.Append oCmd.CreateParameter("p4", 200, 1, 10, "jpg") oCmd.Parameters.Append oCmd.CreateParameter("p5", 7, 1, , Now()) oCmd.Execute Set oCmd = Nothing参数类型 200 是 adVarChar,3 是 adInteger,7 是 adDate。这里的细节是:Access 的 OLEDB 驱动支持?占位符,配合ADODB.Command能有效避免 SQL 注入,同时中文备注信息也不会出现乱码。连接字符串要按服务器环境选:32 位系统用Provider=Microsoft.Jet.OLEDB.4.0,64 位系统需要用Provider=Microsoft.ACE.OLEDB.12.0,否则会直接报“未找到提供程序”。这条经验在我维护老虚机时反复用到,记下来能省一晚上排查时间。
4. 把上传脚本升级成图片管理后台:列表、分页、删除与缩略图
4.1 列表页与分页查询:用 RecordSet 的 AbsolutePage 做分页
上传脚本能存了,管理后台的下一步是让运营能看到图片、找到图片。经典 ASP 的分页不推荐拼TOP加子查询,最省事的做法是用 ADODB.RecordSet 自带的分页能力。核心就三个属性:CursorLocation、PageSize、AbsolutePage,组合起来即可实现翻页。
<% Dim iPage : iPage = CInt(Request.QueryString("page")) If iPage < 1 Then iPage = 1 Dim rs : Set rs = Server.CreateObject("ADODB.RecordSet") rs.CursorLocation = 3 ' adUseClient,客户端游标才能用 AbsolutePage rs.Open "SELECT filename, savepath, filesize, uploadtime FROM pics ORDER BY uploadtime DESC", Conn, 1, 3 rs.PageSize = 20 rs.AbsolutePage = iPage Dim i For i = 1 To rs.PageSize If rs.EOF Then Exit For Response.Write "<img src='" & rs("savepath") & "' onload=""if(this.width>200){this.width=200}"" />" Response.Write "<p>" & rs("uploadtime") & " | " & rs("filesize") & " 字节</p>" rs.MoveNext Next rs.Close Set rs = Nothing %>rs.Open的第三个参数 1 是 adOpenKeyset,第四个参数 3 是 adLockOptimistic,这里读场景用游标类型影响不大,但CursorLocation = 3一定不能省,服务端游标不支持AbsolutePage。列表页按上传时间倒序排列,最新传的图排最前,符合运营查看习惯。onload降级方案在后面小节讲。翻页链接直接拼?page=,比如<a href="list.asp?page=2">下一页</a>,简单粗暴但够用。
4.2 删除、重命名与目录归集
后台管理离不开删除。删除的逻辑顺序有个讲究:先删物理文件,再删数据库记录。如果先删记录、文件删除失败,磁盘上会留下孤儿文件,越积越多;反过来先删文件、记录删除失败,最多出现一条死链,重跑一次删除就能恢复。完整的删除脚本是接收id参数,查出savepath,用 FSO 删文件,再用参数化 SQL 删记录。
<% Dim delId : delId = CLng(Request.QueryString("id")) Dim rsDel : Set rsDel = Conn.Execute("SELECT savepath FROM pics WHERE id=" & delId) If Not rsDel.EOF Then Dim sPath : sPath = Server.MapPath(rsDel("savepath")) Dim fsoDel : Set fsoDel = Server.CreateObject("Scripting.FileSystemObject") If fsoDel.FileExists(sPath) Then fsoDel.DeleteFile sPath Conn.Execute "DELETE FROM pics WHERE id=" & delId End If rsDel.Close Response.Redirect "list.asp" %>这段代码里id用了CLng做类型转换,能挡住大部分 SQL 注入。重命名在图片管理里使用频率不高,我的习惯是只改数据库里的filename和savepath字段,不移动物理文件,避免文件路径变动导致缓存失效。目录归集建议按年月分层,比如/uploads/2025/04/,好处是备份和清理都按时间块走。实现上在保存前拼接子目录字符串,fso.CreateFolder只创建缺失的层级,目录名用四位年份加两位月份补零。
4.3 缩略图实现的两种路径:有组件走组件,没组件就降级
老 ASP 环境生成缩略图是出了名的麻烦。第三方图片组件(常见的是 ASPJpeg 这类)需要服务商在服务器上注册 DLL,很多虚机上根本没有,脚本一旦CreateObject失败直接白屏 500。我的工程习惯是:先探测组件是否存在,存在就生成缩略图,不存在就让列表页直接输出原图,配合前端onload把显示尺寸压下来。上面列表页代码里的onload就是干这个的:图片加载完成后,如果宽度超过 200 像素,就在浏览器端缩到 200,服务端不生成任何新文件。代价是流量还是原图大小,但对几百张图的内网后台完全够用。如果后续流量上来了,再在服务器上装组件,改成上传时同步生成缩略图,列表页就只出小图。这个渐进策略能避免一开始就卡在组件安装上动弹不得。
<img src="/uploads/demo.jpg" onload="if(this.width>200){this.width=200}" />组件探测的写法是On Error Resume Next加Err.Number判断,这个在 ASP 里是标准套路。注意探测和调用要写在同一个页面里,一旦探测通过但调用报错,说明组件版本不兼容,也需要降级处理。
5. 图片上传管理源码部署避坑:5 个真实翻车现场
5.1 传大图没反应:IIS 请求体大小拦住了
现象:小图能传,超过 200KB 左右的图点了上传没反应,有时浏览器转一会儿直接报错。
原因:经典 ASP 在 IIS 6 上默认的AspMaxRequestEntityAllowed只有 200KB 左右,这是服务器层面的硬限制,脚本里不管写多大上限都绕不过。IIS 7 及以上要看两处:ASP功能里的最大请求实体主体限制,以及请求筛选里的maxAllowedContentLength,两处都要调。
解决:IIS 6 在站点属性里找到“ASP”选项卡,把“最大请求实体主体”改大,或者直接改元数据库;IIS 7 以上打开 IIS 管理器,定位站点,双击 ASP,展开“限制属性”,把“最大请求实体主体”改成需要的值,同时确认请求筛选的设置不被覆盖。改完重启 IIS 才生效。这里提醒一句:个人维护的老虚机没有 IIS 管理界面权限时,找服务商要配置支持,自己在 web.config 里改requestFiltering不一定覆盖到 ASP 层。
5.2 中文文件名乱码:客户端编码与服务端代码页不一致
现象:同一个源码,英文文件名上传正常,中文文件名存下来变成????_1.jpg,列表页点开图片 404。
原因:multipart 头里的filename是浏览器按页面编码发送的,服务器代码页(CodePage)如果和页面编码不一致,ASP 解析出来的字符串就是乱码。比如页面是 UTF-8,服务器默认 GBK,MidB切出来的字节按 GBK 解释,得到一串?号。这个问题在无组件上传类里非常经典,根源不是解析逻辑,而是编码设定。
解决:最省心的方法是彻底避开客户端文件名,服务端用时间戳加随机数重新命名,像第 3 章最小版本那样。如果业务一定要保留原始文件名,在脚本顶部统一写<%@ Language="VBScript" CodePage=65001 %>,页面保存为 UTF-8 编码,IIS 的响应头也设成 UTF-8,三层保持一致才能不乱码。我的习惯是永远重命名文件,原始文件名只在数据库里留一个字段做展示用。
5.3 图片保存后打不开:二进制被当成字符串处理
现象:上传成功,数据库里也有路径,但下载到本地 Windows 照片查看器提示“文件已损坏”,用十六进制工具打开看到一堆FF FE开头的 BOM 字符或者中文乱码。
原因:这是无组件上传类最容易翻车的实现。有些源码图省事,把Request.BinaryRead的结果先BytesToStr转成字符串,再用Response.Write或者字符串拼接写文件,等于把二进制图片按文本重新编码了一遍,字节早就变了。只要在保存链路里出现任何“转字符串”的动作,这个文件就废了。
解决:严格按第 3 章的写法,整个数据链路保持二进制:Request.BinaryRead得到字节 →InStrB定位 →MidB切片 →ADODB.Stream.Write落盘,中间不经过任何字符串转换函数。如果你拿到的开源源码已经在BytesToStr这一步翻车了,直接用自己写的二进制解析段替换它,替换范围是“从读取请求体到保存文件”这一整段。
5.4 上传目录报 500:IIS 匿名用户没有写权限
现象:本地调试一切正常,传到服务器上一点上传就 500,事件查看器里提示“拒绝访问”,脚本明明没改过。
原因:Windows 服务器上 IIS 的匿名访问通常走IUSR这个系统账户,上传目录的 NTFS 权限没给IUSR或IIS_IUSRS写入权限,脚本执行SaveToFile时就触发 500。这个问题在虚拟主机上尤其常见,用户只对网站的根目录有写权限,/uploads/子目录建在别的位置,权限对不上。
解决:文件资源管理器里右键上传目录,在“安全”选项卡添加IUSR(Windows Server 2008 之后默认匿名用户是IUSR)并赋予“修改”权限,IIS 的应用程序池身份也要有读写权限。更进一步的安全建议是:上传目录单独建在站点根目录之外,比如D:\PicStore\,脚本用Server.MapPath("../")结合物理路径定位,这样即使上传目录权限给大了,也执行不了站点目录下的脚本文件。
5.5 FSO 组件被禁用:ADODB.Stream 能顶住大半
现象:脚本一执行到Server.CreateObject("Scripting.FileSystemObject")就报“服务器对象”错误,其他功能正常。
原因:不少虚机服务商出于安全考虑,通过注册表把 FSO 组件禁用了,或者干脆没注册。老源码里到处用 FSO 做目录创建、文件判断、文件删除,组件一没,整个上传管理就瘫了。
解决:建目录、删文件这些操作确实依赖 FSO,但传输和落盘可以完全改用ADODB.Stream。第 3 章里我用 FSO 建目录,实际部署时我会先手工把目录建好,脚本里对CreateFolder做容错,并用ADODB.Stream承担读写文件的核心动作。如果连 FSO 的读取都没有,就把依赖 FSO 的代码段扶正:记录日志改用Response直接输出,文件存在性判断改用ADODB.Stream打开试试。总之,目录结构在部署阶段手工规划好,运行时代码只写文件不建目录,这套源码的兼容性立刻上一个台阶。虚拟主机上 FSO 被禁的情况虽然不多,但碰到一次就够折腾一宿。
6. 接手源码后第一件事:安全加固的四个动作
6.1 扩展名白名单与图片魔数双重校验
老源码里最常见的漏洞就是只校验Content-Type,而Content-Type是客户端随意伪造的。我第一次做安全加固时用了一个笨办法:读文件前四个字节,比对图片魔数。JPG 的开头是FF D8 FF,PNG 是89 50 4E 47,GIF 是47 49 46 38,WEBP 走RIFF加WEBP。只有扩展名在白名单里、魔数也对得上,才放行落盘,否则直接拒绝。这个双重校验成本极低,却把“上传一个伪装成图片的 ASP 脚本”这条路堵死了。
Dim bHead : bHead = MidB(bData, iDataStart, 4) Dim oHead : Set oHead = Server.CreateObject("ADODB.Stream") oHead.Type = 1 : oHead.Open oHead.Write bHead oHead.Position = 0 Dim i, sHex : sHex = "" For i = 1 To 4 sHex = sHex & Right("0" & Hex(AscB(MidB(bHead, i, 1))), 2) Next oHead.Close If Left(sHex, 6) <> "FFD8FF" And Left(sHex, 8) <> "89504E47" And Left(sHex, 6) <> "474946" Then Response.Write "文件内容不是合法图片" Response.End End If十六进制字符串比对是兼容性最好的做法,老虚机上不需要额外装任何组件,纯脚本就能跑。
6.2 上传目录去掉脚本执行权限
图片目录只要允许执行脚本,它就成了整个站点的后门。在 IIS 管理器中定位到上传目录,打开“处理程序映射”,点击右上角“编辑功能权限”,取消“脚本”勾选,只保留“读取”。这样即使有人绕过魔数校验传上去一个.asp文件,IIS 也只是把它当静态文件返回源码,不会执行。这个设置优先级很高,是接手遗留源码后的必选项。
6.3 文件名重写、路径穿越与防盗链
文件名统一重写成服务端生成的随机名,既能解决编码问题,又能防路径穿越。很多老源码直接拿filename里的路径拼接Server.MapPath,如果文件名里带../,文件就会写出上传目录,这是高危行为。重写之后,客户端输入在文件系统层面完全失去控制权。防盗链可以在列表页对图片请求做校验,简单做法是检查HTTP_REFERER,不是本站来源就返回空图。老虚机上配置麻烦的话,至少保证图片目录不带脚本权限,再配合随机文件名,图片地址没法被猜测,比防盗链更实际。
接手第一套老 ASP 上传管理源码时,我把安全加固放在功能改造前面,结果第二个月就拦下了一次异常上传:请求体带着一个伪装成 JPG 的脚本文件,扩展名白名单被绕过,但魔数校验挡住了它。那之后我给手上所有遗留系统都补了这道校验。技术栈可以老,安全底线不能降,这套逻辑放在 ASP 上管用,放在任何上传系统上都管用。希望帮到你。
本文还有配套的精品资源,点击获取