
1. 项目概述从“若依”框架的流行说起最近在和一些做安全测试的朋友交流发现一个挺有意思的现象无论是企业内部的渗透测试还是SRC安全应急响应中心的漏洞挖掘实战Ruoyi框架国内开发者更习惯叫它“若依”的管理系统出现的频率越来越高。这其实不难理解作为一个基于Spring Boot和Vue.js的开源后台管理系统它功能齐全、文档友好、生态活跃很多中小型公司甚至一些大厂的内部系统都直接用它作为基础进行二次开发。这就好比一个小区里如果家家户户都用了同一个品牌的智能门锁那研究这个门锁的潜在弱点其价值不言而喻。所以今天我想以一个从业者的视角深入聊聊针对Ruoyi框架管理系统的漏洞挖掘。这不仅仅是复现几个已知的CVE更重要的是分享一套在面对这类“框架型”应用时的系统性挖掘思路。很多新手朋友一上来就拿着扫描器一顿乱扫结果往往不尽人意要么是误报一堆要么是啥也扫不出来。其实针对Ruoyi这类结构清晰、源码开放的系统我们有更高效、更深入的方法。这篇文章我会结合我自己的实战经验从环境搭建、代码审计、功能点测试到漏洞利用一步步拆解目标是让你看完后不仅能复现已知漏洞更能建立起独立挖掘新漏洞的能力。2. 核心思路为什么Ruoyi框架是绝佳的“练兵场”在深入技术细节之前我们必须先理解为什么选择Ruoyi框架作为漏洞挖掘的对象。这决定了我们后续所有工作的方向和重点。2.1 目标价值分析高价值目标的普遍性Ruoyi框架的价值首先体现在它的“普遍性”上。它是一个典型的企业级应用脚手架。这意味着什么意味着它不是一个功能单一的小工具而是一个包含了用户管理、角色权限、菜单管理、部门管理、字典管理、操作日志、定时任务、代码生成等数十个模块的完整后台体系。很多公司为了快速上线业务会直接基于Ruoyi进行开发只修改前端页面和部分业务逻辑底层框架和通用模块尤其是权限校验、文件上传、数据导出等往往原封不动地继承下来。这就带来了一个巨大的攻击面。如果你在Ruoyi官方版本中发现了一个漏洞那么所有未做针对性修复的衍生系统都可能存在同样的风险。这种“一挖一片”的特性使得针对Ruoyi的漏洞研究具有极高的投入产出比。无论是用于企业内部的安全自查还是SRC的漏洞提交成功率都相对较高。2.2 技术栈优势前后端分离带来的清晰攻击链Ruoyi采用前后端分离架构前端Vue 后端Spring Boot这从安全研究的角度看其实是个优点。它让攻击界面变得非常清晰。后端Spring Boot这是我们挖掘逻辑漏洞、越权、SQL注入、命令执行等传统Web漏洞的主战场。Spring Boot的注解式开发如PreAuthorize、拦截器、AOP等机制是我们审计权限校验是否完备的关键。同时MyBatis作为ORM框架其XML中动态SQL的编写方式是SQL注入的常见风险点。前端Vue.js前端并非无懈可击。它负责参数传递、输入校验和界面展示。我们可以通过分析前端代码来推测后端接口的预期行为寻找参数篡改、接口未授权访问等漏洞的线索。例如前端对某个字段做了长度限制但后端没做就可能存在存储型XSS或缓冲区溢出的风险虽然Java中后者较少见。此外前端路由、API请求的封装方式也可能泄露敏感信息或接口路径。这种清晰的分离允许我们分别从两个层面进行深入分析然后再结合起来寻找由于前后端校验不一致导致的“缝隙”。2.3 审计友好性开源与结构规整Ruoyi是完全开源的代码托管在Gitee和GitHub上。这意味着我们可以获得最纯净、最官方的源代码进行白盒审计这是黑盒测试无法比拟的优势。其代码结构遵循典型的Spring Boot项目规范模块划分清晰如admin模块处理后台业务system模块是系统核心控制器Controller、服务Service、数据访问层Mapper分层明确。这种规整性极大地降低了审计的复杂度。我们可以快速定位到负责用户登录的LoginController负责文件上传的CommonController或者负责数据导出的工具类。相比于审计一个代码风格混乱、结构庞杂的遗留系统在Ruoyi上更容易形成系统性的审计路径也更容易发现那些因框架特性或开发者习惯而产生的“模式化”漏洞。3. 环境准备与信息收集磨刀不误砍柴工在开始挖掘之前搭建一个“靶场”并充分收集信息是至关重要的第一步。这里我推荐的方式不是直接下载一个打包好的漏洞环境而是从官方仓库拉取源码自己构建和运行。3.1 本地环境搭建从源码到可运行系统获取源码访问Ruoyi的官方Gitee仓库选择你感兴趣的版本分支通常master或最新的稳定版即可。使用git clone命令拉取到本地。导入IDE使用 IntelliJ IDEA 或 Eclipse 等Java IDE打开后端项目。使用VSCode或WebStorm打开前端项目。确保你的本地环境已安装JDK 8、Maven 3.x、Node.js 和 npm。数据库初始化在MySQL中创建一个新数据库如ry然后执行项目sql目录下的初始化脚本。这一步会创建所有的表结构和默认数据包括默认管理员账号admin/admin123。配置修改修改后端application.yml或application-druid.yml中的数据库连接配置指向你刚创建的数据库。启动项目后端在IDE中直接运行RuoYiApplication主类或使用mvn spring-boot:run命令。前端进入前端目录运行npm install安装依赖然后运行npm run dev启动开发服务器。访问验证浏览器打开http://localhost:80前端默认端口应该能看到登录页面。使用默认账号登录完整浏览一遍所有功能模块。注意我强烈建议你在本地搭建环境而不是使用现成的Docker镜像或在线靶场。本地环境允许你随时修改代码、打断点调试、查看实时日志这对于理解漏洞成因和构造利用链至关重要。这是“知其然并知其所以然”的关键。3.2 信息收集与资产梳理绘制你的“攻击地图”系统跑起来后先别急着上工具。花点时间手动浏览和梳理你会得到比扫描器更精准的信息。功能模块清单登录系统后左侧菜单栏就是最直观的功能清单。逐一访问系统管理用户、角色、菜单、部门、岗位、字典、系统监控在线用户、定时任务、数据监控、系统工具表单构建、代码生成。记录下每一个功能点的URL路径和操作方式。接口API枚举打开浏览器的开发者工具F12切换到Network网络选项卡。清空记录然后在前端页面上进行各种操作点击查询、新增、删除、导出等。你会看到大量发往后端的XHR请求。记录下这些请求的URL、方法GET/POST/PUT/DELETE、参数格式JSON/Form-Data和可能的请求头如Authorization Token。这些是后续测试的直接入口。技术指纹确认虽然我们知道是Spring Boot但可以进一步确认细节。观察HTTP响应头通常会有X-Application-Context,Server等信息。访问一些默认路径如/actuator/health(Spring Boot Actuator监控端点)/error等观察其返回特征。确认使用的权限框架是Spring Security还是ShiroRuoyi常用的是Spring Security 自研权限注解。敏感文件与目录探测使用目录扫描工具如dirsearch, gobuster或手动尝试探测是否存在.git源码泄露、/swagger-ui.htmlAPI文档、/druid数据库监控面板、/actuator端点等。这些往往是薄弱环节。通过以上步骤你手里应该有一份详细的“攻击面地图”有哪些功能、对应哪些接口、使用了什么技术。接下来我们就可以按图索骥进行深度挖掘了。4. 白盒代码审计从框架机制到业务逻辑有了源码和运行中的系统白盒审计是我们的核心武器。审计不是漫无目的地看代码而是有策略、有重点地推进。4.1 权限校验机制审计寻找越权的突破口权限漏洞垂直越权、水平越权是后台管理系统的高发漏洞。Ruoyi通常使用PreAuthorize注解或自定义拦截器来实现方法级权限控制。审计切入点全局搜索PreAuthorize注解。查看其表达式例如PreAuthorize(ss.hasPermi(system:user:list))。这个表达式调用了ss这个Bean的hasPermi方法。关键检查缺失注解寻找那些执行敏感操作增删改查、文件操作的Controller方法是否遗漏了PreAuthorize注解。一个常见的疏忽是开发者给查询列表的接口加了权限但忘了给导出Excel的接口加。注解误用检查注解中的权限字符串是否与菜单/按钮配置的权限标识符严格一致。有时会出现拼写错误或逻辑错误例如本应是system:user:remove删除却写成了system:user:list查询。水平越权校验这是重点中的重点。即使有PreAuthorize注解它通常只校验“你有没有操作这个功能的权限”而不会校验“你能不能操作这个特定对象”。例如修改用户信息的接口/system/user/update它校验了hasPermi(system:user:edit)但传入的用户ID参数userId后端是否验证了当前登录用户只能修改自己或自己部门下的用户这需要深入Service层或Mapper层查看SQL语句或业务逻辑中是否包含了基于当前用户身份如部门ID、创建人的数据过滤条件。如果没有就可能存在通过修改userId参数来修改他人信息的水平越权。实操心得我习惯先从前端入手。用浏览器工具查看一个正常请求的参数然后尝试修改参数如ID、用户名重放请求。同时在IDE中对对应的Controller方法打上断点单步调试观察权限校验逻辑和数据查询逻辑是如何执行的。这样能最直观地发现问题。4.2 SQL注入与ORM框架审计MyBatis的动态SQL陷阱Ruoyi使用MyBatis作为数据持久层。MyBatis本身是安全的风险来自于不安全的动态SQL拼接。审计切入点在resources/mapper目录下查看所有*.xml文件。重点关注使用了if,choose,when,otherwise,foreach等动态SQL标签的地方。高危模式${}的使用MyBatis中#{}是预编译占位符能防止SQL注入而${}是字符串替换直接将参数拼接到SQL语句中极其危险。全局搜索${任何在where、order by、like等子句中使用${}接收用户输入的地方都是潜在的注入点。例如排序字段order by ${orderByColumn}如果orderByColumn用户可控就可能引发注入。模糊查询中的likelike %${keyword}%是典型错误写法。应使用like concat(%, #{keyword}, %)或like % || #{keyword} || %取决于数据库。in语句的动态拼接使用foreach遍历集合构造in语句时确保传入的是List类型并使用#{item}取值而不是拼接字符串。黑盒验证对于发现的疑似${}注入点在前端对应功能进行测试。例如在搜索框或排序字段中尝试输入、\、1 and 11等payload观察响应是否有语法错误或结果异常。更精确的方法是使用时间盲注payload如1 and sleep(5)--观察请求响应时间。4.3 文件操作与反序列化审计通往RCE的路径文件上传、下载、读取和反序列化是获取服务器权限RCE的常见入口。文件上传定位到文件上传的Controller通常是CommonController中的upload方法。检查后缀名过滤是黑名单还是白名单黑名单极易被绕过如.jsp、.jspx、.phP等。白名单是否足够严格内容类型检查是否只检查了Content-Type这个可以被轻易篡改。文件内容校验是否检查了文件头Magic Number对于图片是否进行了二次渲染或压缩这能有效破坏植入的恶意代码。存储路径与访问权限上传的文件是否存储在Web可访问目录下是否使用了随机文件名目录路径是否用户可控路径穿越漏洞任意文件读取/下载搜索download、readFile、getFile、InputStream、ResponseEntityResource等关键词。检查文件路径参数如fileName、filePath是否用户可控是否进行了严格的路径校验防止../../etc/passwd这类路径穿越攻击。反序列化搜索ObjectInputStream、readObject、JSON.parseObjectFastjson等库、XMLDecoder、XStream等关键词。任何反序列化用户可控数据的地方都是极端高危的。Spring Boot默认使用的Jackson库在特定配置下也可能存在反序列化问题如启用DefaultTyping。5. 黑盒功能点测试模拟攻击者的视角白盒审计给了我们“上帝视角”但黑盒测试能模拟真实攻击者的行为两者结合才能覆盖更全面。5.1 越权测试实战从垂直越权到水平越权垂直越权权限提升低权限用户尝试高权限操作创建一个只有基础查看权限的测试账号。登录后直接通过浏览器工具捕获高权限操作如添加用户、修改角色的请求用低权限账号的会话Cookie/Token去重放这个请求。观察响应是“权限不足”还是“操作成功”。接口路径猜测/遍历管理员操作的用户管理接口可能是/admin/user/add那么/admin/role/add、/admin/config/add呢尝试对已知路径进行目录遍历和参数爆破。水平越权数据访问越权ID参数篡改这是最经典的测试。用户A登录后查看或编辑自己的信息请求如GET /system/user/profile或POST /system/user/update其中包含一个ID参数可能是userId也可能是从Token中解析但有时会冗余传递。尝试将这个ID修改为用户B的ID重放请求。订单、文章、地址等业务对象任何具有“所属用户”概念的业务数据都是水平越权的测试重点。例如查看订单详情接口/order/detail?id1001尝试将id改为1002属于其他用户的订单。5.2 注入与XSS测试自动化与手工的结合SQL注入自动化扫描使用sqlmap这类工具是高效的但要对准目标。将前面信息收集阶段抓到的请求特别是带参数的GET/POST请求保存到文件用sqlmap加载测试。重点测试排序、搜索、筛选功能。手工测试对于时间盲注等复杂场景手工测试更灵活。在可能注入的点输入1 AND SLEEP(5)--观察响应延迟。同时监控后端应用日志看是否打印了异常的SQL语句。XSS跨站脚本反射型XSS测试所有用户输入并立即回显的地方如搜索框、URL参数。输入scriptalert(1)/script或img src1 onerroralert(1)等基础payload。存储型XSS测试所有能保存数据并在其他页面展示的功能如用户昵称、评论内容、文章标题、系统公告等。注入的脚本会被存入数据库当其他用户尤其是管理员浏览相关页面时触发。DOM型XSS这需要分析前端JavaScript代码。寻找从location.hash、document.referrer、window.name等来源获取数据并直接使用innerHTML或eval进行操作的代码片段。5.3 逻辑漏洞挖掘业务流中的陷阱逻辑漏洞往往最难通过工具发现也最具破坏性。并发竞争条件在涉及状态转换和数量限制的地方测试。例如优惠券/积分领取限制每人领取一张。同时发起多个领取请求使用Burp Suite的Turbo Intruder或Python多线程看是否能突破限制。支付流程支付成功后的回调处理是否没有做好幂等性校验可能被重复调用导致多次发货或充值。业务流程绕过步骤跳过一个多步骤的操作如申请-审核-发布能否直接调用最后发布的接口跳过前面的校验参数干扰在修改个人资料的接口除了正常参数是否可以通过添加roleadmin这样的参数来提升自己的权限后端是否只更新了提交的字段而没有过滤掉不该由用户更新的字段验证码与防重放验证码是否可绕过发送短信或邮件验证码的接口是否在验证码校验成功前就完成了业务操作如重置密码验证码是否可复用使用过的验证码在有效期内是否还能再次使用请求是否可重放一个重要的交易请求如转账缺少有效的防重放令牌Token导致可以被截获后重复执行。6. 漏洞利用与深度利用链构造发现漏洞只是第一步如何证明其危害性Proof of Concept, PoC至关重要这决定了漏洞的评级和修复优先级。6.1 从信息泄露到权限提升假设我们发现了一个未授权访问的接口/system/config/list它能列出系统配置其中包含邮件服务器的SMTP密码或云存储的AK/SK。基础利用直接访问获取敏感信息。深度利用如果泄露的是后台管理员的会话Token可能通过日志接口、错误信息泄露我们可以直接接管管理员会话。如果泄露的是数据库连接密码可以尝试连接数据库进一步获取所有用户密码哈希虽然Ruoyi密码是加盐加密的但可能存在弱口令用户或者直接修改用户数据来提升权限。6.2 组合漏洞形成攻击链单个漏洞可能危害有限但组合起来就能产生“化学反应”。案例文件上传 路径穿越 - RCE发现文件上传功能对后缀名过滤不严可以上传.jsp文件。但同时上传路径被写死在了/profile/upload/。似乎无法访问。进一步测试发现图片查看功能存在路径穿越/common/download?fileName../../../../profile/upload/evil.jsp。攻击链形成先上传evil.jsp的Webshell到固定路径再通过路径穿越漏洞去访问和执行它最终获得服务器命令执行权限。案例水平越权 信息泄露 - 全面数据泄露通过水平越权A用户能访问B用户的订单列表接口。该列表接口返回了每个订单的详细ID。结合另一个订单详情接口同样存在水平越权或未授权就可以遍历获取所有用户的完整订单数据。6.3 编写高质量的漏洞报告在SRC或内部提交漏洞时报告质量直接关系到审核效率和奖金。清晰标题简明扼要如“Ruoyi管理系统后台存在未授权访问漏洞可泄露敏感配置信息”。详细步骤提供一步步的复现操作从登录什么账号开始点击哪里输入什么数据看到什么结果。最好附上截图或视频。完整请求/响应提供Burp Suite或浏览器抓取的原始HTTP请求和响应包关键部分用箭头或高亮标出。危害分析说明这个漏洞能导致什么后果数据泄露、权限提升、系统控制等。结合业务场景分析其影响范围。修复建议给出具体的、可操作的修复方案。例如“在/system/config/list接口的Controller方法上添加PreAuthorize(\ss.hasPermi(system:config:list)\)注解。” 而不是笼统地说“加强权限校验”。7. 防御建议与安全开发规范作为挖掘者我们不仅要会攻更要理解如何防。针对Ruoyi框架的常见漏洞给开发者一些切实可行的建议。7.1 权限校验的黄金法则默认拒绝原则所有接口默认都应要求认证和授权。使用Spring Security的配置或全局拦截器实现。注解全覆盖对所有业务接口方法显式添加PreAuthorize注解并使用白名单方式声明所需权限。数据级权限校验在Service层或Mapper层必须加入基于当前用户身份的数据过滤。例如update操作前先查询该数据是否属于当前用户或其管辖范围。可以使用ThreadLocal存储用户上下文在MyBatis的SQL中通过插件自动添加dept_id #{currentUser.deptId}等条件。7.2 SQL注入与XSS的根治之道MyBatis强制使用#{}在代码规范中明确禁止在${} 中传入用户可控参数。如需动态排序应在后端将参数值映射为安全的枚举值。全局XSS过滤与转义后端在HttpMessageConverter层或使用过滤器对请求参数进行统一的HTML转义如使用Apache Commons Text的StringEscapeUtils.escapeHtml4。对于富文本内容使用如Jsoup等白名单库进行严格的HTML过滤。前端在Vue中使用{{ }}插值会自动转义HTML。对于需要渲染HTML的情况使用v-html指令时要确保内容绝对安全或先进行过滤。CSP内容安全策略在HTTP响应头中配置Content-Security-Policy可以有效缓解XSS的危害即使脚本被注入也无法加载外部资源或执行内联脚本。7.3 文件与反序列化的安全边界文件上传“白名单重命名隔离存储”三件套后缀名白名单如只允许.jpg,.png,.pdf。文件内容头校验检查Magic Number。使用UUID等随机字符串重命名文件避免被猜测。将文件存储在Web根目录之外通过一个安全的下载控制器来读取和传输文件该控制器必须进行严格的路径校验和权限校验。杜绝不安全的反序列化完全避免使用ObjectInputStream反序列化网络数据。如果必须使用序列化如Redis缓存应确保信道安全TLS并考虑使用对称加密序列化数据。对于JSON反序列化禁用Jackson的DefaultTyping等危险特性。7.4 依赖组件与安全配置定期升级依赖使用Maven的versions:display-dependency-updates插件定期检查并升级Spring Boot、MyBatis、Fastjson等所有第三方库及时修复已知漏洞。关闭不必要的端点在生产环境中务必在application.yml中关闭Spring Boot Actuator的所有敏感端点或将其访问权限限制在内部网络。management: endpoints: web: exposure: include: health # 只暴露健康检查端点 endpoint: health: show-details: never安全的错误处理自定义全局异常处理器避免将Java异常栈、SQL错误等信息直接返回给前端。应返回统一的、友好的错误消息。漏洞挖掘是一个需要耐心、细心和系统化思维的过程。Ruoyi框架作为一个优秀的开源项目其代码本身是学习和研究Web安全的绝佳样本。我希望通过这篇长文不仅提供了一些具体的漏洞点和测试方法更重要的是传达了一种“从框架机制入手结合白盒黑盒系统性分析”的挖掘思路。在实际操作中你可能会遇到更复杂的情况或者我文中提到的一些问题在新版本中已经被修复但这套方法论是通用的。最后请务必在合法授权的环境下进行所有安全测试技术应用于正道才能创造真正的价值。