SpringBoot+Vue在线教育(在线学习)系统代码审计
字数 3708
更新时间 2026-02-27 12:08:28

SpringBoot+Vue在线教育系统代码审计教学文档

摘要

本文档基于一篇关于“SpringBoot+Vue在线教育(在线学习)系统”的代码审计报告,详细阐述了该系统在搭建、鉴权机制及多个安全漏洞方面的内容。报告针对一个基于若依框架二次开发的闭源项目,采用SpringBoot + Vue2技术栈,并揭示了包括JWT密码爆破、Druid越权、任意文件上传、未授权访问和垂直越权在内的关键安全风险。

一、 系统概述与环境搭建

该系统为一个在线教育平台,主要特点如下:

  • 技术栈
    • 后端:SpringBoot + MySQL + Redis
    • 前端:Vue2,分为前台 (learn_front-master) 和管理后台 (learn_front_mange-master) 两部分
    • 鉴权:采用 Shiro + JWT 模式
  • 环境搭建步骤
    1. 后端:修改数据库配置文件中的账号密码,导入SQL表结构,启动MySQL和Redis服务。
    2. 前端:由于采用Vue2,在项目根目录下使用 npm run serve 命令启动前端服务。

二、 鉴权机制分析

系统的安全入口点在于ShiroConfigJwtToken的配置。

  1. ShiroConfig:配置了URL的访问规则。除了注册、登录界面以及一些必要的静态资源接口(如学校列表、用户头像)被放行外,其他所有路由均需通过JWT令牌验证
  2. JwtFilter:核心的请求过滤器。其isAccessAllowed方法会调用executeLogin进行验证,验证的核心是getSubject(request, response).login(jwtToken);,这行代码会将JWT令牌提交给自定义的Realm进行校验。
  3. ShiroRealm:自定义的Realm类,内部逻辑清晰地展示了如何验证JWT令牌的合法性,是后续漏洞挖掘的关键切入点。

三、 漏洞挖掘与详情

审计发现了多个中高危安全漏洞。

3.1 基于JWT的密码爆破漏洞

  • 漏洞位置ShiroRealmJwtUtil 类。
  • 漏洞成因
    1. ShiroRealm的验证逻辑中,发现生成JWT令牌的语句为:JwtUtil.sign(userId, password);
    2. 跟进JwtUtil.sign方法,发现其使用HMAC256算法,密钥(secret)是用户的密码(userPhone变量,实际为密码)。签名生成的令牌仅包含了userId声明。
    3. 由于签名密钥是用户密码,攻击者一旦获知某个用户的userId,即可在不触发登录失败记录的情况下,离线暴力破解该用户的密码。攻击方式是通过不断尝试密码生成新的JWT令牌,然后使用该令牌访问正常接口,侦察难度极高。
  • 攻击路径
    1. 获取userId:系统存在信息泄露。在前台的教师列表功能中,点击查看教师详情,响应数据包中会返回该教师的userId
    2. 实施爆破:利用获取到的userId和已知的JWT生成算法,编写脚本批量尝试密码字典,生成JWT令牌并测试其有效性。

3.2 Druid监控台越权访问 + 弱口令

  • 漏洞位置:Druid监控台 (/druid 路径) 及配置文件。
  • 漏洞详情
    1. 越权访问:直接访问Druid登录页面会被拦截,提示需要Token。然而,系统未对Druid访问权限做严格校验。一个普通用户注册登录后获得的JWT令牌,可以直接用于访问/druid路径,实现了从普通用户到Druid控制台的水平越权
    2. 弱口令:在配置文件application-dev.yml中,Druid监控台的管理员账号密码为默认或简单的弱口令。
  • 组合风险:攻击者可以先注册普通账号,然后利用越权访问进入Druid登录页面,再通过弱口令直接登录管理后台,获取数据库监控、SQL执行等高危操作权限。

3.3 前台任意文件后缀上传(可导致XSS)

  • 漏洞位置CommonController 控制器。
  • 漏洞成因
    1. 控制器提供了三个上传接口:uploadImg(上传图片)、uploadVideo(上传视频)、uploadFile(上传文件)。
    2. 其中,只有uploadImg对文件后缀进行了白名单检查uploadFileuploadVideo接口未对文件后缀做任何限制,允许上传任意后缀的文件。
  • 验证与利用
    1. 构造一个包含HTML内容的文件(如xss.html),通过/common/uploadFile接口上传。
    2. 上传成功后,返回可访问的静态文件路径,直接访问该路径可触发前端XSS攻击。
  • 限制:由于Spring框架对文件名进行了规范化处理,无法通过../实现路径穿越上传到Web目录之外。虽然可以上传.jsp/.jspx等服务器脚本文件,但由于被存储在静态资源目录,会被作为普通文件下载,无法解析执行。

3.4 未授权访问漏洞

  • 漏洞位置:课程内容访问与评论相关接口。
  • 漏洞详情
    1. 课程内容未授权访问
      • 正常流程:学生(test3)报名课程后,需等待教师(test2)在后台审核通过,才能观看课程章节内容。
      • 漏洞:教师审核后,学生获得一个包含特定参数(如任务ID)的章节内容访问链接。攻击者(另一个未通过审核的学生)如果直接使用这个链接,即可绕过权限校验,直接访问到课程内容
      • 根本原因:后端控制器中处理章节内容查询的方法(如getApeTaskById没有对当前请求用户的权限(是否属于该课程、是否被审核通过)进行校验,仅根据传入的ID返回数据。
    2. 未授权评论
      • 漏洞原理同上。评论接口未校验用户与课程的关联权限。
      • 攻击者只需抓取一个合法用户(如已审核的学生test2)发表评论的数据包,然后将其中的JWT令牌替换成自己的令牌(test3)进行重放攻击,即可实现未授权评论。

3.5 垂直越权漏洞(普通用户提升为教师)

  • 漏洞位置:用户信息修改接口 (/user/setUserInfo)。
  • 漏洞成因
    1. 用户在前台修改个人信息时,会向/user/setUserInfo接口发送POST请求,请求体中包含完整的用户对象ApeUser的字段。
    2. 后端接口在更新用户信息时,没有对可修改的字段做任何过滤或鉴权。特别是没有校验用户是否被允许修改userType这样的关键权限字段。
    3. 数据库中的userType字段定义:0代表管理员,1代表教师,2代表学生。
  • 攻击演示
    1. 以一个学生身份 (userType=2) 登录,抓取修改个人信息的数据包。
    2. 在JSON请求体中,找到"userType":2,将其修改为"userType":1
    3. 重放该数据包,后端会直接更新数据库。此时,该学生的身份在系统内即变更为教师,获得教师权限。

四、 总结与修复建议

该系统在权限控制上存在严重缺陷,多处关键接口缺乏服务端校验。

漏洞类型 风险等级 修复建议
JWT密码爆破 高危 1. 修改JWT生成算法,切勿使用用户密码作为签名密钥。应使用系统统一的、强密码学强度的随机密钥。2. 对用户密码进行强复杂度要求,并增加密码错误尝试锁定机制。
Druid越权+弱口令 高危 1. 在Shiro配置或拦截器中,/druid/**路径添加基于角色的访问控制,只允许管理员IP或特定角色访问。2. 修改Druid监控台的默认账号密码,并设置为强口令。
任意文件上传 中危 1. 对所有文件上传接口统一实施严格的白名单策略,只允许业务必需的后缀。2. 对上传文件进行重命名(如使用UUID),并避免直接使用用户原始文件名。3. 将上传文件存储在非Web根目录或通过静态资源服务器处理,降低直接执行风险。
未授权访问 高危 1. 在所有业务接口的入口处,添加细粒度的权限校验。例如,在getApeTaskById等方法中,需验证当前用户是否有权限访问该任务ID对应的资源。2. 建议使用Spring Security或Shiro注解,在方法级别进行权限控制。
垂直越权 严重 1. 禁止通过普通接口修改核心权限字段(如userType)。更新用户信息时,只允许更新非敏感字段2. 采用“更新模型”与“实体模型”分离的策略,如使用DTO接收参数,并过滤掉不应由前端传入的字段。3. 在服务端逻辑中,强制覆盖userType等字段为会话用户的原始值。

总体安全建议:在项目开发中,必须遵循“永不信任客户端输入”和“最小权限原则”。所有权限判断必须在服务端进行,并对用户可操作的数据范围进行严格限定。

 全屏