1. 项目概述一次对教育数字化底线的“体检”最近几年教育信息化进程加速各类在线教学、考试、阅卷系统如雨后春笋般涌现。作为一名长期关注应用安全的研究者我习惯性地会对身边这些新上线的系统保持一份“好奇心”。这次的目标是一个在本地多所学校推广使用的“网上阅卷系统”。它号称能实现试卷扫描、客观题自动判分、主观题在线批阅、成绩统计分析全流程数字化听起来非常高效便捷。但我的直觉告诉我越是这种承载着高利害关系学生成绩、教师评价的系统其安全防线可能越脆弱因为开发者的首要目标往往是功能实现和用户体验安全常常被置于次要位置。这次“挖掘”更像是一次非官方的、出于责任心的安全“体检”我想看看在光鲜的界面背后是否存在可能被利用的薄弱环节。网上阅卷系统本质上是一个B/S架构的Web应用通常涉及教师、学生或考生、管理员等多种角色业务流程复杂包含上传、批改、查询、统计等多个环节。任何一个环节的逻辑设计疏忽或技术实现缺陷都可能演变为严重的安全漏洞。我的目标很明确在不影响系统正常服务、不触碰真实数据的前提下以授权测试或研究的心态尝试发现其中可能存在的安全隐患并理解其成因。这不仅能帮助相关方提升安全意识对于安全从业者而言也是一次绝佳的实战学习机会可以深入理解业务逻辑与安全技术的交汇点。2. 前期侦察与信息收集摸清“战场”地形在动手测试之前盲目的扫描和攻击是低效且危险的。我的第一步永远是尽可能多地收集目标信息这就像战前侦察了解对方的兵力部署技术架构和防御工事安全措施。2.1 目标系统指纹识别首先我通过浏览器访问了系统的登录页面。查看网页源代码是获取基础信息的捷径。我迅速发现了几个关键线索前端框架页面中引用了特定的JavaScript库和CSS文件例如vue.js和element-ui这暗示前端可能基于Vue.js框架开发。现代前端框架本身安全性较高但与之交互的后端API是重点。HTTP响应头通过浏览器开发者工具或curl命令查看服务器返回的HTTP头。我发现了Server: nginx/1.18.0和X-Powered-By: PHP/7.4.33。这直接揭示了Web服务器是Nginx后端语言是PHP。PHP版本是7.4.33这是一个已经停止官方安全维护的版本EOL这本身就是一个潜在的风险点意味着已知的公开漏洞可能无法得到官方补丁。URL结构与参数浏览了几个功能页面发现URL模式多为/index.php?madmincscoreaquery或/api/student/getList?page1limit20。前者是典型的基于MVC框架如ThinkPHP的URL路由形式后者则是更现代化的RESTful风格API。混合架构可能意味着系统是逐步迭代开发的不同模块的安全水平可能不一致。注意信息收集阶段的所有操作都应限制在公开可访问的页面上避免触发入侵检测系统IDS/WAF。使用curl -I获取头部、whatweb或Wappalyzer浏览器插件都是常用且低调的方法。2.2 目录与接口探测有了基础信息下一步是发现更多隐藏的入口点。我使用了dirsearch工具配合一个适中的字典对目标域名进行目录和文件扫描。目的是寻找备份文件如.bak,.zip,.tar.gz,wwwroot.zip配置文件如.env,config.inc.php管理后台入口如/admin/,/manage/,/backend/未引用的API接口文档如/swagger/,/api-doc/测试或示例文件扫描结果中除了已知的功能页面我发现了一个/phpinfo.php文件。访问后果然是一个未删除的phpinfo()信息页。这相当于一张系统的“体检报告”暴露了大量敏感信息PHP配置如allow_url_include是否开启、已安装的扩展、服务器路径、环境变量等。这是一个低级但极其危险的错误配置我立即记录下这个发现。同时还发现了一个/upload/目录直接列出了所有上传的文件这属于目录遍历漏洞可能泄露用户上传的试卷图片等敏感资料。2.3 账户体系与业务逻辑初探为了理解业务逻辑我尝试注册了一个测试账号如果开放注册或者分析登录、找回密码等流程。这个系统需要学校统一分配账号因此我转而仔细研究其登录和会话管理机制。 通过拦截登录请求我发现登录成功后服务器返回了一个名为auth_token的字段并在后续请求中客户端通过在HTTP请求头Authorization: Bearer token的方式携带该令牌。这是JWTJSON Web Token或无状态会话的常见做法。我需要验证这个Token的强度是否可预测是否过期时间过长是否在注销后依然有效3. 漏洞挖掘实战从外围到核心的渗透信息收集完毕后我心中已经绘制了一张初步的“攻击面地图”。接下来就是按照风险优先级逐一进行测试验证。3.1 入口点漏洞SQL注入与文件上传SQL注入测试我选择了几个看似最有可能存在注入的点登录表单、成绩查询接口、用户信息查询接口。使用Burp Suite拦截这些请求对每一个参数无论是GET还是POST进行篡改。经典探测在参数值后附加单引号观察返回错误。在查询学生列表的API/api/student/getList?nametest中我将name参数改为test返回了数据库错误信息明确提到了SQL语法错误。这证实了存在SQL注入漏洞。漏洞利用进一步我使用sqlmap工具进行自动化验证和利用。命令如下sqlmap -u http://target.com/api/student/getList?nametest --batch --dbs很快sqlmap成功识别出注入点并获取了数据库列表。我发现系统使用了MySQL库名包含exam_db。通过注入我能够枚举表名、字段名甚至提取数据。这里暴露的根本问题是后端在拼接SQL语句时未对用户输入进行有效的过滤或使用预编译语句Prepared Statements。文件上传漏洞测试我找到了试卷图片上传的功能点。尝试上传一个正常的.jpg图片成功。然后我尝试进行绕过修改文件扩展名将一句话木马文件shell.php重命名为shell.jpg然后通过Burp修改上传数据包中的filename为shell.php。系统后端仅检查了文件名未校验文件内容上传成功。双扩展名绕过上传shell.jpg.php。Content-Type绕过将shell.php的Content-Type改为image/jpeg。 经过测试其中一种方式成功上传了PHP文件并且可以通过浏览器直接访问/upload/shell.php来执行任意代码。这结合之前发现的目录遍历危害极大攻击者可以直接获取服务器控制权。3.2 业务逻辑漏洞越权与数据篡改业务逻辑漏洞往往比技术漏洞更隐蔽也更难通过自动化工具发现需要深入理解业务流程。水平越权假设我以学生A的身份登录我的用户ID是1001。系统有一个查看“我的试卷详情”的接口/api/paper/detail?paper_id5001。我尝试将paper_id参数改为5002推测是学生B的试卷请求竟然成功返回了学生B的试卷详情和分数。这说明系统在验证用户权限时只检查了会话是否有效但没有校验当前用户是否有权访问paper_id5002这份资源。这就是典型的不安全的直接对象引用IDOR。垂直越权我注意到普通教师和管理员可能共用一套前端代码权限控制仅靠前端菜单隐藏或按钮禁用。通过拦截普通教师登录后的请求我分析其API返回的菜单数据发现其中包含了一个标记为hidden: true的管理员功能菜单项。我直接手动构造访问该隐藏功能对应API的请求例如添加系统用户的API/api/admin/user/add由于后端缺乏对接口级别的角色校验该请求被执行成功。这属于功能级访问控制缺失。分数篡改逻辑漏洞这是网上阅卷系统最核心、最敏感的业务。我仔细测试了教师批阅后提交分数的流程。拦截提交分数的POST请求发现其数据结构类似于{ exam_id: 2024001, student_id: 1001, questions: [ {qid: 1, score: 5}, {qid: 2, score: 10}, ... ], total_score: 150 }我尝试修改了student_id为其他学生或者修改某个题目的score为超出满分限制的值如满分10分我提交15分。测试发现修改student_id后分数被错误地记录到了另一个学生名下严重的越权数据篡改。提交超限分数时后端竟然接受了并在总分计算中使用了这个非法值。这说明后端缺乏关键的业务规则校验一是未二次确认分数归属二是未对单项分数进行合法性校验如是否在0-满分之间。3.3 会话与认证漏洞Token的安全性问题回顾登录时获取的auth_token。我使用jwt.io这个在线工具对其进行解码无需密钥仅查看结构。发现它是一个简单的JWT包含用户ID、角色和过期时间exp但签名部分使用的是弱密钥或默认密钥。更严重的是exp字段设置得非常遥远比如一年后这意味着Token一旦泄露在很长一段时间内都有效。 我尝试了以下攻击Token篡改由于怀疑密钥强度弱我使用工具jwt_tool尝试对Token进行暴力破解或已知弱密钥测试试图伪造一个高权限如管理员的Token。注销机制测试在客户端点击“退出登录”后我依然用旧的Token去访问需要认证的API发现仍然可以成功访问。这说明服务端没有有效的Token吊销机制会话管理是有状态的可能在服务端存储了Token白名单但注销时并未从白名单中移除该Token。4. 漏洞成因深度分析与修复建议发现漏洞只是第一步理解其背后的成因才能提出有效的修复方案这也是安全研究的价值所在。4.1 技术层面成因安全意识缺失与安全开发流程SDL未落地phpinfo.php文件遗留、目录列表开启这些都是运维和开发中最低级的错误表明项目从上线到运维缺乏基本的安全检查和清理流程。SQL注入和文件上传漏洞则直接指向开发人员未经过安全编码培训对用户输入持有绝对信任。依赖过时且有风险的组件PHP 7.4已停止维护意味着已知的漏洞如某些特定版本的PHP漏洞无法通过官方升级修复需要自行 backport 补丁或承担风险。权限校验逻辑设计缺陷这是业务逻辑漏洞的根源。系统采用了“通过隐藏来实现安全”的前端控制思维而忽视了最根本的“服务端每次请求都必须进行权限校验”的原则。校验逻辑分散、不统一甚至缺失。会话管理不当JWT使用弱密钥、超长过期时间、无吊销机制使得Token一旦泄露即造成持久性风险。JWT适用于无状态场景但系统业务明显需要状态管理如强制下线、注销技术选型与业务需求不匹配。4.2 修复方案建议针对以上漏洞我整理了一份简要的修复建议清单漏洞类型风险等级修复建议信息泄露(phpinfo, 目录遍历)中1. 立即删除phpinfo.php等测试文件。2. 在Web服务器Nginx配置中关闭目录列表功能 (autoindex off;)。3. 对upload等资源目录设置访问规则禁止脚本执行。SQL注入高危1. 全面启用参数化查询预编译语句。2. 对现有代码进行审计对所有数据库操作函数进行替换。3. 使用ORM框架避免手写SQL。文件上传漏洞高危1. 白名单校验文件扩展名和MIME类型。2. 对上传文件进行重命名如使用随机哈希值避免直接使用用户提供的文件名。3. 将文件存储在Web根目录之外通过脚本动态读取和输出。4. 对图片文件进行二次渲染如图片压缩破坏潜在的恶意代码。越权访问 (IDOR)高危1.服务端增加资源所有权校验。在每一个涉及资源ID的API中从可信的会话信息如Token中的user_id出发验证该用户是否有权访问/操作目标资源。2. 使用统一的权限校验中间件。功能级越权高危1. 实现基于角色/权限的访问控制RBAC。2. 在后端为每一个API接口标注所需权限并在请求到达控制器前进行拦截校验。业务逻辑漏洞 (分数篡改)严重1. 提交分数时student_id必须从当前登录教师会话或不可篡改的上下文中获取而非来自请求体。2. 对每一项分数进行严格校验是否为正数是否小于等于该题满分3. 总分应由后端根据各题分数计算而非信任前端传递。会话管理问题中1. 使用强随机密钥对JWT进行签名并定期轮换。2. 设置合理的Token过期时间如2小时。3. 实现Token黑名单/吊销机制将注销或修改密码后的Token加入黑名单。4. 考虑在敏感操作如修改分数、添加用户时进行二次认证。5. 反思与总结教育类系统安全的特殊性这次对网上阅卷系统的漏洞挖掘让我对教育行业应用安全有了更深的体会。这类系统有几个显著特点也放大了安全风险数据敏感性极高学生成绩、个人信息属于高度敏感数据。一旦泄露或篡改不仅侵犯个人隐私还可能影响升学、评价等重大利益引发严重的社会问题。用户群体庞大且复杂用户包括学生、教师、家长、管理员角色多样权限模型复杂。很容易在权限设计上出现疏漏导致越权。开发运维压力大教育信息化项目往往预算有限、工期紧张。承建方可能是一些中小型软件公司其安全开发能力和安全意识参差不齐。学校作为使用方也普遍缺乏专业的安全运维人员。等保合规要求这类系统通常需要满足网络安全等级保护等保的要求。其中很多中高危漏洞如SQL注入、越权是等保测评中的“一票否决”项。因此对于教育类系统的安全建设绝不能停留在“事后打补丁”的阶段。必须从软件开发生命周期SDLC的源头入手将安全需求纳入设计对开发人员进行安全编码培训在上线前进行严格的安全测试白盒黑盒渗透测试并建立常态化的安全监控和应急响应机制。对我个人而言这次实战是一次宝贵的经验积累。它再次印证了“漏洞往往存在于复杂业务的结合部”这一观点。自动化工具能发现常见的技术漏洞但那些深藏于业务流程中的逻辑漏洞更需要测试者具备“攻击者思维”去理解业务去问“如果我是恶意用户我会怎么滥用这个功能”。保持这份好奇心和对细节的执着是安全研究者最重要的品质之一。最后所有这类测试必须在获得明确授权的前提下进行并将发现的问题通过合规渠道如SRC平台上报这才是负责任的安全研究之道。