news 2026/10/1 4:54:32

RuoYi框架安全攻防:从漏洞挖掘到加固实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RuoYi框架安全攻防:从漏洞挖掘到加固实践

这套系统有个老版本,部署特别多,所以挖这类目标的时候第一件事就是判断版本。框架本身一直在更新,但真正跑在公网上的,大量还是停留在两三年以前的版本,那批版本里的问题基本是明牌。

2.1 先看懂攻击链路:请求进来之后发生了什么

一套ruoyi后端,典型的请求链路是:Nginx -> Spring Boot应用 -> Shiro/Spring Security过滤器链 -> Controller -> Service -> Mapper(MyBatis)-> MySQL/Redis等存储组件。要挖漏洞,就要在链路的每一环找"可被操纵"的点。

有相当一部分注意力放在权限控制层。老版本用的是Apache Shiro,新版本里有Spring Security版本,两者的鉴权机制差别很大。Shiro那条线,核心在ShiroConfig里配置的匿名URL和过滤器链顺序;Spring Security那条线,核心在SecurityConfig里对/login、/register、验证码接口这些"白名单"路径的放行方式。这里经常出现的低级问题就是:开发为了让某个接口不被拦截,直接加到anonymous或permitAll列表里,结果这个接口本身是敏感接口(比如查询全部用户、修改配置)。

还有一种很容易被忽视的情况是拦截器/注解的覆盖范围不一致。框架里接口权限用的是@PreAuthorize("@ss.hasPermi('system:user:list')")这类注解,但Controller层如果漏写注解,而全局配置又没有兜底策略,这个接口就变成了"登录即可访问",甚至"未登录即可访问"。我在实际测试里见过不少这类案例,业务方为了省事,在自定义Controller里直接调用SysUserService的敏感方法,却没加任何权限注解。

2.2 核心组件的老化程度:Shiro之外的"定时炸弹"

除开鉴权组件,还有几个组件的高频问题值得关注:

  • Quartz定时任务:框架自带"定时任务"管理页面,允许管理员配置cron表达式、调用目标bean和方法。核心风险在于,任务调用的目标是反射拼接的,如果某个版本的配置校验不够严格,就可以"调用到"一些危险类的危险方法。虽然这个功能需要管理员权限,但配合越权或弱口令,就能形成完整攻击链。更重要的是,Quartz本身还涉及反序列化问题(org.quartz.impl.jdbcjobstore),如果用了JDBCJobStore,且库里的QRTZ_JOB_DETAILS表能被通过SQL注入等方式写入恶意序列化数据,那也是RCE,不过这条链路的利用门槛比Shiro反序列化高不少。

  • Druid监控页面:框架带Druid数据库连接池,druid.stat.view.servlet如果暴露出去,未授权就能看到SQL监控、Session监控等敏感信息,有时候还能直接看到内网地址。老版本里默认路径是/druid,且部分部署连登录页都没配置。这不算多高级的漏洞,但在SRC上报里属于有效信息,CNVD也认。

  • Redis:新版配置里Redis密码是硬编码在application-druid.yml里的,如果Redis端口暴露到公网、密码是弱口令,攻击者可以通过Redis写文件或者Spring Session反序列化,进一步控制应用。这类问题在部署不规范的目标里很常见,虽然根因不在ruoyi框架本身,但框架默认给你配好了,用的人没有安全意识,就白给了。

2.3 代码生成器与在线用户管理:被人忽视的"信息泄露口"

框架自带的代码生成器(tool/gen相关接口,在老版本里是/tool/gen,新版是/tool/gen基础上加了权限)在默认情况下需要管理员权限,但如果版本较老或权限校验缺失,就可能未授权访问,直接把数据表的字段结构、注释、实体类代码全部暴露出来。数据库表结构本身就是很有价值的信息,表字段就是攻击者的地图。

在线用户管理(/monitor/online)会展示当前登录用户的Session ID和登录IP,如果这个接口未授权可访问,攻击者可以直接强退他人会话,甚至结合Session固定思路做进一步利用。

这些点都不是"拿shell"级别的漏洞,但它们是漏洞挖掘里很好的"敲门砖",能帮你快速积累对目标系统的认知,判断后续往哪个方向深挖。

3. 五类高频漏洞形态与触发逻辑

下面结合我在授权测试和个人研究里的实际观察,梳理五类在ruoyi里反复出现的高频漏洞。每一类我都说一下触发逻辑,尽量不写具体利用代码,重点讲怎么发现和判断,因为防御方更需要的是"识别"能力。

3.1 反序列化:Shiro默认密钥与硬编码AES Key

老版本ruoyi使用Shiro,而Shiro的"RememberMe"功能使用了AES-CBC加密序列化数据,密钥写在ShiroConfig里。框架历史上有一段时间用的是官方文档里的默认值fCq+/xW489hGYDVHRVFcNQ==(不同版本有不同默认值),很多部署根本没改。攻击者只要用这个密钥自己构造恶意序列化对象,加密后放进Cookie,服务器就会在反序列化时执行命令。

这个漏洞的检测很简单:请求/login时往Cookie里塞一个用默认密钥加密的序列化对象,观察响应是否异常。修复方案就是生成随机Key,升级Shiro版本(新版框架已移除Shiro)。我在实际测试中遇到最难缠的情况是:目标改了默认Key,但只改了这一个Key,org.apache.shiro:shiro-core里的其他反序列化gadget链仍然存在,只是没了入口。这种"改了一半"的情况很常见。

新版框架如果迁移到了Spring Security,这类漏洞就自然消失了,但对应地会出现Spring Security自身的配置风险,比如HttpSecurity.authorizeRequests()规则写错。

3.2 定时任务:表达式注入与危险调用

Quartz定时任务模块在框架里叫"定时任务",页面里可以新建任务,填写"调用目标"(比如ryTask.ryParams)和cron表达式。框架做了很多安全过滤,比如限制包名前缀、校验cron表达式等,但版本的演进过程中,都有对应的绕过方式。

我印象比较深的是某个版本里,调用目标的类名过滤是基于黑名单的,把javax.naming、org.apache.commons.collections这些常见的危险包给拦了,但漏了JDK自带的com.sun.rowset.JdbcRowSetImpl(JNDI注入),配合Spring Boot内置的Tomcat,可以走ELProcessor表达式执行。修复方案也很简单:把"调用目标"的解析改成白名单,只允许调用预设的Service方法。

从漏洞挖掘角度看,这类型问题需要注意的前提是:定时任务管理页面本身需要管理员权限。所以绝大多数情况下,它的利用路径是"先拿到管理员会话,再通过定时任务getshell"或者"存在越权,普通用户也能访问该接口"。如果目标系统能未授权直接访问定时任务页面,那价值就非常高了。

3.3 文件上传:后缀校验与路径穿越的"组合拳"

框架自带的文件上传一般走/common/upload,存储路径在配置文件里。这类漏洞的核心难点不在于"能不能传",而在于"传上去之后能不能被解析成代码"。漏洞挖掘里常见的问题是:

  • 校验只防了后缀,没防Content-Type,或者校验了后缀但没防大小写(.JSP、.PhP在被解析时可能因为Tomcat配置而被识别为jsp)。
  • 上传接口对路径参数校验不严,存在路径穿越,可以把文件写到webapps/ROOT外的任意目录。
  • 上传后文件名用了原始文件名,导致恶意文件直接落在静态资源目录下可访问。

我在给一套自建系统做授权测试时,遇到过ruoyi的上传接口本身没什么问题,但业务方在代码里自定义了一个上传接口,直接copy框架代码,把校验逻辑删得只剩if (file.isEmpty()),这就全白给了。

3.4 SQL注入:别只盯着MyBatis的${}

MyBatis框架本身对#{}做了预编译,所以注入点往往在${}拼接的地方,比如排序字段、表名、IN语句参数、LIKE模糊搜索的拼接逻辑。ruoyi的BaseEntity里有params字段,常用作查询条件,比如params[beginTime]、params[dataScope],如果开发图省事直接在Mapper.xml里做了${params.dataScope}拼接,立刻就是SQL注入。

还有一类容易被忽略的是**druid监控页面的SQL日志**,它本身不执行SQL,但会展示连接池执行过的SQL文本,如果页面未授权访问且前端没有对拼接内容做转义,攻击者可以通过构造畸形参数让SQL日志里出现特殊内容,虽然这不算SQL执行漏洞,但会泄露业务数据接口。

3.5 越权与未授权:低危名称下的高影响力

框架的自带功能里,我建议重点看两个方向:

一是IDOR/水平越权。框架很多实体都继承了BaseEntity,主键用的是自增ID或雪花ID,自定义接口经常直接用前端传的ID去查询。比如/system/notice/notice/1可以查公告,那改成/2、/3呢?业务方如果不做数据权限过滤,就是水平越权。

二是垂直越权/未授权访问。框架提供了一堆/monitor/*、/tool/*开头的接口,有些版本在配置匿名URL时把整个/monitor/**放行了,里面的/monitor/online、/monitor/cache都能未授权访问。这些信息看似不痛不痒,但能帮助进一步攻击。

4. 授权范围内从零到一的完整挖掘流程

接下来按实操顺序,把整个挖掘流程走一遍。前提:所有操作都在授权范围内进行,最好有书面授权书,遵守《网络安全法》及相关法规。

4.1 指纹识别:先确认它确实是ruoyi

第一步永远是判断目标是不是ruoyi。有几种可靠的识别方式:

  • 访问/login页面,看HTML源码里有没有ry-logo、vue项目编译后的资源路径、#/login这类特征。
  • 请求/prod-api/前缀(新版前后端分离默认路由前缀)下的接口,看响应头或错误信息。
  • 直接访问/druid/index.html,如果返回200,基本实锤是Java系且大概率ruoyi。
  • 登录页面的"验证码"接口:GET /captchaImage返回一张base64图片和一个uuid,这也是ruoyi的特征。
  • 查看/favicon.ico的MD5(如果没被改),网上已经有ruoyi默认图标的Hash库。

判断完版本范围之后,再去做下一步。

4.2 API路径测绘:把路由面拉出来

老版本的前端页面和后端接口是分离的,接口文档在/swagger-ui.html或/doc.html(knife4j)。如果这两个页面能访问,那接口列表直接是白给,下面的步骤都可以简化。

如果文档被关闭了,可以按下面的方式来测绘:

  • 先确定接口前缀:新版是/prod-api,老版本有的用/,有的自己配了server.servlet.context-path。
  • 使用常规的轻量级目录扫描工具(比如dirsearch/ffuf),字典里重点覆盖/system/user/list、/system/role/list、/tool/gen/list、/monitor/online/list、/common/download等框架常用路径。
  • 拦截器在响应header里可能泄露X-Requested-With: XMLHttpRequest,也可作为判断接口是否为异步请求的辅助特征。

测绘过程中我给个建议:结合前端JS文件一起看。登录后把static/js目录下的app.js、chunk-*.js拉下来,直接搜url:后面的字符串,能拿到一版"被注释掉的、被隐藏起来的"接口列表,这是纯黑盒目录扫描找不到的。

4.3 验证与利用:从"可能"到"确定"

一个可疑接口确认漏洞,通常需要三次请求:

  1. 未登录请求:确认返回码(若返回401或302说明有鉴权;若返回200且带业务数据,说明疑似未授权)。
  2. 带普通用户Token请求:确认水平越权或垂直越权。
  3. 针对具体漏洞类型的有效载荷请求:比如SQL注入就构造成1 and 1=1与1 and 1=2看响应差异。

这里要特别强调证据留存。完整记录请求包、响应包、时间戳,这些是写报告、提交SRC时必须的材料。CNVD和SRC平台很看重可复现性,你只写"存在SQL注入"是没有分量的,得附上请求包、注入点、影响的表或payload示例(注意脱敏)。

4.4 报告撰写:决定漏洞能否落地

报告的价值占整个漏洞挖掘工作的一半。一份好报告要讲清楚:

  • 漏洞URL、参数、请求方法。
  • 影响的系统版本与组件版本,便于修复方定位代码。
  • 完整的复现步骤(截图或请求包)。
  • 危害说明:不浮夸,也不贬低。
  • 修复建议:尽量具体(比如"升级xx版本至x.x.x""在ShiroConfig中将密钥改为随机值""修改Druid监控页访问权限")。

提交SRC时,漏洞等级判定主要看利用成本和影响范围。同样是Shiro反序列化,如果目标在内网、无法访问,分值和可利用性都有限;如果直接暴露公网且能出网,那就是严重。

5. 我在实战中踩过的坑:给你提个醒

这部分内容是纯经验,不写网上到处都是的东西,只讲那些绕了很多弯路才明白的事情。

5.1 版本差异导致的"假阳性"与"假阴性"

有一次,我测试一个目标时,用老版本Shiro利用链打过去,发现Cookie反序列化没有任何反应。我判断目标没有漏洞,但后来仔细翻包,发现目标根本没有优先加载Shiro的过滤器,而是先被前端网关拦截了。也就是说,目标系统可能套了一层其他代理,我的payload根本没到后端。这种情况下,报告写"否"就漏报了。

反过来,也有"假阳性":用扫描器扫出来某个接口"疑似SQL注入",但其实是该接口对畸形输入做了统一异常处理,返回固定错误页面。所以,所有自动扫描结果都必须手工复核,这一步绝对不能省。

5.2 开发环境与生产环境的"版本漂移"

源码审计和在线测试对不上号的情况非常多。一套生产系统,代码基于上游ruoyi二开,但二开时把shiro.ini、application.yml改了很多,甚至把某个功能模块从下游框架里抽出来重写了。这就导致你在Gitee上看的源码与目标实际情况完全两样。要避免这个问题,尽量以在线行为观测为准,源码分析只作为辅助判断。

5.3 授权边界与测试范围:保护自己才是第一要务

很多做漏洞挖掘的新人容易忽略:授权书里写的范围是哪个域名、哪些IP段、允许的时间窗口。有的目标因为业务联动,会导致你访问到第三方系统(比如CDN、OSS、第三方登录),这些一旦越界,麻烦非常大。我在实际操作中,会用浏览器插件加一个"当前测试目标"的提示条,看清域名才发请求,同时所有非授权目标一律不碰。

5.4 别把"框架漏洞"和"业务漏洞"混为一谈

提交漏洞时,尽量区分"框架自身问题"和"业务方二开引入的问题"。这两个的修复责任方不同:前者是升级框架、打补丁;后者是业务方在私有代码里改逻辑。有些SRC平台因为目标绑定的主体不同,对两类漏洞的确认和打分差异很大。我在报告里会明确写"该问题在框架默认配置下即存在"或"该问题由业务方自定义上传逻辑导致",这样审核方省力,自己也免得被驳回。

6. 从防御视角看:部署一套"不好打"的ruoyi要做哪些事

如果你刚好是使用这套框架的运维或开发,最后这部分是写给你们的。我在前面挖了这么多窟窿,现在反过来给加固建议。

6.1 版本升级是第一优先级

框架的Gitee官方仓库持续在更新,去掉了很多已知问题。别再守着老版本了。升级之前重点看两个东西:数据库结构变化和配置项变化。老版本升到新版,不只是替换jar包,数据库里的sys_config、sys_menu可能会有增量数据,菜单权限表也可能会变化,升级前做好备份和测试环境演练。

6.2 组件密钥与配置项的收敛

逐一检查这些配置项:

  • ShiroConfig里的AES密钥:如果用老版本,改成随机生成,长度至少16字节。
  • Redis密码:不要留空,不要用123456,最好用带特殊字符的长密码。
  • druid.stat.view.servlet.enabled:如果不需要监控页,直接设为false;需要的话加账号密码和IP白名单。
  • application.yml里的server.servlet.session.timeout:不要太长,降低会话固定风险。

6.3 网关/WAF层的防护

不要只依赖框架自身的过滤器,在Nginx层把该禁的路径先禁了:

  • 对/druid/**、/swagger-ui.html、/v2/api-docs、/doc.html做访问限制或直接拒绝。
  • 自定义业务上传接口时,尽量用对象存储(OSS等),别把文件落在本地web目录。
  • 配置限流,防止登录接口被爆破;登录接口加验证码,框架自带这个功能,一定要开启。

6.4 日志与监控

ruoyi自带/monitor/operlog和/monitor/logininfor,能记录操作日志和登录日志。开启后能让你在攻击发生后的很短时间内发现问题。我在一次授权测试里,刚扫完接口列表就在/monitor/operlog里看到了红字告警,那是业务方自己接的日志系统弹出来的,识别速度很快,这也能看出来日志真正发挥作用时的价值。

另外建议在Nginx层加一个“访问频率异常”的告警规则,很多自动化攻击的特征就是短时间内大量请求不同的URL,及时感知就能在漏洞被利用前切掉入口。

写在最后:把这套流程变成你自己的方法论

这篇内容没有详细展开具体某个漏洞的完整利用路径,因为公开环境下讨论利用细节的尺度需要克制,而且脱离了授权场景讨论利用本身没有意义。我更希望传递的是一套“如何在合规前提下,把一个开源框架的系统漏洞挖清楚、讲明白”的流程和思维。

我自己在多年的测试里反复体会到的几件事,拿出来共勉:

  • 漏洞挖掘不是比谁工具多、跑的字典大,而是比谁对系统原理理解更深。把框架生命周期、组件调用链、鉴权模型的底层逻辑吃透,很多“看着没有漏洞”的系统,其实到处是破绽。
  • 授权是底线,报告是门面。一个漏洞无论多简单,只要在授权范围内、报告写得清晰规范,它就是有价值的成果;反之,没有授权的漏洞挖掘,哪怕技术再炫,也是害人害己。
  • 多关注上游更新和社区的通报,很多漏洞不是“挖出来的”,是“等出来的”。框架每次发版修复的问题,往往就预示着同一个问题在所有运行实例里都还存在,只是还没有人公开利用而已。

如果你正准备入门漏洞挖掘,拿ruoyi这套框架练手是很好的选择:源码开放、案例丰富、社区活跃,可以同时练习代码审计和黑盒测试。但记得在自己搭的靶场环境里练,或者只针对有授权的目标,安全这条红线什么时候都不能越。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 4:54:32

EEG脑电信号分类技术体系全解析:从传统方法到深度学习实战

1. 为什么EEG分类值得单独写一篇体系化梳理脑电信号分类这个方向,我前前后后跟了快六年,从最早拿SVM加手工特征跑二分类,到后来用CNN做端到端,再到现在折腾图神经网络建模电极间拓扑关系,踩过的坑比跑通的实验多得多。…

作者头像 李华
网站建设 2026/10/1 4:54:32

基于CNN的网络入侵检测实战:从特征编码到模型部署

简介:基于卷积神经网络实现网络入侵检测的完整项目代码包,面向希望掌握深度学习与网络安全结合应用的小白和进阶学习者,适合用于毕业设计、课程设计或工程实训。包内提供数据预处理脚本、一层全连接层对照代码和CNN主程序,配套KDD…

作者头像 李华
网站建设 2026/10/1 4:54:31

并行归约、区间贪心与树状数组:execution环境下的算法工程实践

最近在做一套综合性的算法与计算优化练习,项目标题是“execution并行归约|区间贪心|树状数组”。乍一看这三个词像是从不同教科书里硬凑出来的——并行归约是高性能计算里的经典操作,区间贪心是算法设计课的常客,树状数组则是竞赛选手人手一份的数据结构。但把它们放到同一个执…

作者头像 李华
网站建设 2026/10/1 4:53:34

Jev架构:面向业务执行闭环的AI决策系统范式

1. Jev 不是新名词,而是决策系统演进的必然结果你可能在最近几周的技术社区、架构分享会甚至招聘JD里反复看到“Jev”这个词——它不像Transformer或Diffusion那样自带论文出处,也不像Kubernetes或Flink那样有明确的开源仓库和版本号。它没有官网首页弹窗…

作者头像 李华
网站建设 2026/10/1 4:52:48

Keil调试实战指南:从环境配置到HardFault排查,把调试窗口用起来

Keil软件程序调试学习笔记:从环境配置到实战排查,把调试窗口真正用起来做嵌入式开发的人,几乎没人绕得过Keil。不管你是刚点完LED灯的新手,还是正在调电机FOC的老手,只要你手上跳过的板子用的是STM32、GD32、C51&#…

作者头像 李华
网站建设 2026/10/1 4:52:47

Codex接入Jev完整指南:配置、踩坑与本地部署实践

Codex 这个终端里的 AI 编程助手,最近在开发者圈子里热度一直没下来。它的定位和传统的补全插件完全不同——不是帮你少敲几行代码,而是像一个坐在终端里的初级工程师:给它一个任务,它自己读仓库、定位问题、改文件、跑命令&#…

作者头像 李华