若依框架安全加固:五个高危配置自查清单与实战修复指南

📅 2026/7/19 5:29:56 👁️ 阅读次数 📝 编程学习
若依框架安全加固:五个高危配置自查清单与实战修复指南

1. 项目概述:为什么若依框架需要一份安全自查清单?

若依(RuoYi)作为国内Java开发者圈子里普及度极高的开源后台管理系统脚手架,其“开箱即用”的特性极大地加速了企业级应用的开发进程。无论是单体版、前后端分离版,还是集成了工作流(Flowable)或微服务(Cloud)的版本,它都提供了丰富的模块和代码生成器。然而,也正是因为其“脚手架”的定位,许多开发者(包括我早期)容易陷入一个思维误区:认为框架本身是安全的,或者默认配置就是最佳实践。这恰恰是最大的安全隐患。

在实际的渗透测试和代码审计工作中,我见过太多基于若依开发的项目,因为开发者直接沿用默认配置或未理解框架的安全机制,导致系统门户大开。攻击者几乎可以拿着公开的漏洞利用脚本“按图索骥”。这份清单,正是源于我多次为团队项目做安全加固和应急响应后,总结出的、开发者最容易忽略或误配的五个高危点。它不是一份全面的安全指南,而是一份聚焦于“配置”和“常见漏洞”的实战检查单。目的是让你在开发、测试、上线前,花上半小时快速过一遍,堵住那些最容易被利用的缺口。

2. 高危配置一:脆弱的默认密码与未改动的密钥

这是最经典也最致命的问题。若依框架为了演示方便,内置了默认的管理员账号(admin/admin123)和默认的加密密钥。在正式环境中不修改它们,等同于把家门钥匙放在门口的垫子下面。

2.1 默认密码的危害与排查

危害:攻击者通过弱口令爆破或直接使用默认凭证,可直通系统后台,获得最高权限。后续的数据窃取、植入后门、横向渗透都将易如反掌。

自查与修复步骤

  1. 修改内置用户密码

    • 路径:系统启动后,必须立即使用admin/admin123登录。
    • 操作:进入“系统管理” -> “用户管理”,找到admin用户,点击“修改”。务必使用强密码(建议12位以上,包含大小写字母、数字、特殊字符)。同时,检查并禁用或删除其他测试账号,如ry/123456
    • 原理:这不仅仅是改一个密码,更是切断了一条最直接的攻击路径。许多自动化攻击脚本的第一步就是尝试默认口令。
  2. 重置应用加密密钥

    • 关键文件ruoyi-common/src/main/resources/application.yml(单体)或各微服务模块的bootstrap.yml/application.yml
    • 关键配置项:查找token.secretaes.secretjwt.secret等配置。若依使用这些密钥进行Token签名、数据加密等。
    • 操作绝对不能使用源码中或网上示例里的默认值。必须使用强随机字符串替换。例如,可以使用在线工具或命令行(如openssl rand -base64 32)生成一个足够长且随机的字符串。
    # 错误示例(使用默认或简单密钥) token: secret: abcdefghijklmnopqrstuvwxyz0123456789 # 正确示例(使用生成的强随机密钥) token: secret: L8q6Zc7NwV5pXk2H9jF1rT0yS3dE4bG7aMqPwJzKv
    • 注意事项:修改密钥会导致所有已登录用户的Token失效,需要在系统维护时段进行操作。修改后,务必重启应用。

实操心得:我曾审计过一个项目,其token.secret竟然是公司名的拼音。攻击者一旦通过其他信息泄露猜到密钥,就可以伪造任意用户的登录态(JWT Token),实现“越权登录”。密钥的强度直接决定了会话安全的下限。

3. 高危配置二:过度暴露的接口与信息泄露

若依集成了Swagger、Druid监控等优秀组件,方便开发和调试。但在生产环境,它们可能成为信息泄露的源头。

3.1 Swagger API文档的未授权访问

危害:Swagger-ui页面暴露了所有Controller接口的路径、参数、甚至数据结构。攻击者无需阅读源码即可了解系统全部API,并可以在此界面直接发起请求,进行参数探测和漏洞测试。

自查与修复

  1. 生产环境必须禁用或严格鉴权
    • 方案一(推荐):环境隔离。在application-prod.yml中彻底关闭Swagger。
    # application-prod.yml swagger: enabled: false
    • 方案二:IP/角色白名单。如果确有内部维护需要,可通过Spring Security或拦截器,配置只允许内网IP或特定管理员角色访问/swagger-ui.html/v2/api-docs等路径。
    // 示例:在Security配置中添加规则 http.authorizeRequests() .antMatchers("/swagger-ui.html").hasRole("admin") // 或 .hasIpAddress("192.168.1.0/24") .antMatchers("/webjars/**", "/swagger-resources/**", "/v2/api-docs").permitAll() // 静态资源可放行 .anyRequest().authenticated();

3.2 Druid监控台未授权访问

危害:Druid连接池监控台功能强大,可以查看SQL执行、Session监控、甚至执行Web URI。若未加保护,攻击者不仅能窥探数据库操作,还可能利用其功能进行更深层次的攻击。

自查与修复

  1. 强制添加登录验证:Druid内置了登录验证功能,生产环境必须启用
    # application.yml spring: datasource: druid: stat-view-servlet: enabled: true login-username: your_admin_name # 必须修改! login-password: your_strong_password # 必须修改! allow: 127.0.0.1 # 可设置IP白名单,为空则允许所有(不推荐) deny: # 黑名单
  2. 结合应用安全框架:同样,可以将/druid/**路径纳入Spring Security的管理范围,实现更复杂的权限控制。

避坑技巧:不要仅仅依赖Druid的简单密码验证。在安全要求高的场景,应将其访问路径纳入统一的应用权限管理体系,并记录访问日志。我曾遇到一个案例,攻击者通过搜索引擎的inurl:druid/index.html语法,直接找到了暴露在公网的监控台,并利用弱口令进入,最终拖走了整个数据库的配置信息。

4. 高危配置三:不当的文件上传与目录遍历

文件上传是Web应用的常见功能,也是漏洞高发区。若依的通用上传下载组件如果配置不当,会引入严重风险。

4.1 文件上传漏洞的典型场景

危害:攻击者上传恶意文件(如JSP、PHP Webshell,或包含恶意脚本的HTML),从而获取服务器命令执行权限。

自查与修复要点

  1. 白名单校验文件后缀:这是最重要的防线。不要使用黑名单(禁止某些后缀),因为总有漏网之鱼。应只允许业务必需的后缀。
    // 示例:在文件上传服务中强化校验 public void validateFile(MultipartFile file) { String originalFilename = file.getOriginalFilename(); String suffix = StringUtils.substringAfterLast(originalFilename, ".").toLowerCase(); List<String> allowedSuffixList = Arrays.asList("jpg", "jpeg", "png", "gif", "pdf", "doc", "docx"); if (!allowedSuffixList.contains(suffix)) { throw new RuntimeException("不允许上传此类型文件"); } // 进一步检查文件魔数(Magic Number),防止伪造后缀 }
  2. 重命名存储文件:不要使用用户上传的文件名。应使用UUID等随机名称重命名,避免路径遍历和覆盖攻击。
  3. 设置独立的存储域名和目录:将上传文件存储到与应用服务器分离的目录,并通过Nginx/Apache等Web服务器以静态资源方式提供服务。关键:配置该目录禁止脚本执行权限
    # Nginx 配置示例,禁止指定目录执行PHP、JSP等脚本 location ~* ^/upload/.*\.(php|jsp|asp|aspx)$ { deny all; }
  4. 限制文件大小:在application.yml中配置spring.servlet.multipart.max-file-sizemax-request-size,防止DoS攻击。

4.2 路径遍历漏洞(Directory Traversal)

危害:攻击者通过构造包含../等特殊字符的文件路径参数,访问或上传文件到服务器上的任意目录,如读取/etc/passwd或覆盖系统文件。

自查与修复

  1. 规范化路径:在代码中,对所有用户输入的文件路径参数,进行规范化处理,并检查是否在允许的根目录之内。
    // 使用Apache Commons IO或JDK7+的Paths API String userInputPath = request.getParameter("filePath"); String safeBaseDir = "/var/www/uploads/"; File file = new File(safeBaseDir, userInputPath); String canonicalPath = file.getCanonicalPath(); // 获取规范路径 if (!canonicalPath.startsWith(new File(safeBaseDir).getCanonicalPath())) { throw new IllegalArgumentException("非法路径访问!"); }

经验之谈:我曾处理过一个漏洞,开发者直接使用request.getParameter("fileName")拼接成服务器路径进行文件读取,未做任何过滤。攻击者通过fileName=../../../../etc/passwd成功读取了系统敏感文件。永远不要信任客户端传入的任何路径信息。

5. 高危配置四:失效或不当的访问控制(越权漏洞)

越权漏洞(垂直越权、水平越权)是业务逻辑层面的致命伤。若依虽然提供了基于权限注解(如@PreAuthorize)的框架,但开发者若使用不当,等于形同虚设。

5.1 水平越权:我能操作别人的数据

场景:用户A和用户B属于同一角色,用户A通过修改请求参数(如订单ID、用户ID),能访问或操作用户B的数据。

自查与修复

  1. 服务层强制校验数据归属:这是核心。在每一个涉及数据ID的操作方法中,必须加入归属权判断。
    @GetMapping("/order/{orderId}") @PreAuthorize("@ss.hasPermi('system:order:query')") // 角色权限校验 public AjaxResult getOrder(@PathVariable Long orderId) { // 1. 根据orderId查询订单 Order order = orderService.selectOrderById(orderId); // 2. 关键步骤:校验当前登录用户是否有权查看此订单 Long currentUserId = SecurityUtils.getUserId(); if (!currentUserId.equals(order.getUserId())) { throw new ServiceException("无权访问此订单信息"); } // 3. 返回数据 return AjaxResult.success(order); }
    切记@PreAuthorize注解只解决了“有没有这个权限点”的问题,没解决“这个数据是不是你的”的问题。两者必须结合使用。

5.2 垂直越权:用户拥有了管理员权限

场景:普通用户通过某种方式(如修改前端隐藏字段、直接调用API)访问到了只属于管理员的接口或功能。

自查与修复

  1. 严格使用权限注解:确保所有Controller方法都使用了@PreAuthorize注解,并指定了正确的权限字符串(如@PreAuthorize("@ss.hasPermi('system:user:edit')"))。
  2. 定期审计权限配置:检查sys_menu表中的菜单和按钮权限配置是否准确,确保没有将高权限的perms错误地分配给了低角色。
  3. 不要依赖前端隐藏:永远不要相信前端传来的角色ID、权限标识来做后端鉴权。后端必须从安全的上下文中(如SecurityUtils)重新获取当前用户的真实身份和权限进行判断。

踩坑记录:在一个快速开发的项目中,为了赶进度,开发者给一个“用户管理”的查询接口只加了@PreAuthorize("@ss.hasPermi('system:user:list')"),但忘记在服务层校验查询范围。导致任何有user:list权限的员工,都能通过修改查询参数,列出公司所有员工(包括高管)的敏感信息。权限注解是“门卫”,数据归属校验是“房间锁”,两者缺一不可。

6. 高危配置五:错误的安全依赖与默认配置

框架依赖的第三方组件(如Fastjson、Jackson、Log4j2)或其默认配置,可能自带安全漏洞。

6.1 依赖组件漏洞管理

危害:像Log4j2这样的基础日志组件爆发高危漏洞(如CVE-2021-44228)时,若项目中引入了有漏洞的版本,且使用了危险配置(如开启JNDI查找),系统将面临远程代码执行的极端风险。

自查与修复流程

  1. 定期扫描与升级
    • 工具:使用Maven插件(如mvn versions:display-dependency-updates)或专业的软件成分分析(SCA)工具(如OWASP Dependency-Check、Snyk)定期检查项目依赖。
    • 关注:重点关注序列化库(Fastjson、Jackson)、日志库(Log4j2、Logback)、模板引擎(Thymeleaf、FreeMarker)、数据库驱动等核心组件的安全公告。
  2. 若依框架本身的版本升级:关注若依官方GitHub的Release和Security Advisories。及时将框架升级到已修复已知安全漏洞的版本。

6.2 危险的默认序列化与反序列化配置

危害:若依默认使用Jackson进行JSON序列化。如果接口接收的参数是复杂的泛型或允许指定类名,且配置不当,可能触发不安全的反序列化。

自查与修复

  1. 全局配置Jackson:在配置类中,明确关闭有风险的特性。
    @Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); // 禁用通过JSON字符串反序列化时指定任意类的能力 mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true); // 明确指定序列化/反序列化的可见性 mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE); mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); // 如果使用Polymorphic Deserialization(多态反序列化),必须使用安全的@JsonTypeInfo配置,避免基于类名的反序列化。 return mapper; } }
  2. 谨慎使用@RequestBody Map<String, Object>Object:这类通用参数接收方式,如果后续又使用类似JSON.parseObject(jsonString, User.class)的方式进行转换,且类名来自用户输入,风险极高。应尽量使用明确的DTO对象接收参数。

核心原则:保持依赖的“最小化”和“最新化”。非必要的依赖不引入,必要的依赖及时更新到安全版本。对于框架的默认配置,尤其是涉及数据解析、网络通信、命令执行的,要抱有怀疑态度,查阅官方安全文档进行加固。

7. 构建持续的安全自查流程

安全不是一次性的配置,而应融入开发运维的全生命周期。以上五个高危点是一个起点,你需要建立一个持续的流程。

  1. 代码提交门禁:在Git仓库配置pre-commitpre-receive钩子,使用静态代码分析工具(如SonarQube、Fortify SCA)扫描代码,将“硬编码密码”、“不安全的反序列化”等规则作为强制检查项。
  2. CI/CD集成扫描:在持续集成流水线中,集成依赖漏洞扫描(SCA)和动态应用安全测试(DAST)工具。每次构建都自动生成安全报告。
  3. 定期人工审计:每季度或每次重大迭代后,按照本清单进行人工走查。重点关注新增的接口、配置变更和引入的新组件。
  4. 监控与响应:确保应用日志(尤其是认证、授权、文件操作、敏感数据访问日志)被完整收集和监控。设置告警规则,对异常登录、高频错误请求、敏感路径访问等行为进行实时告警。

安全本质上是一种“成本”与“风险”的平衡。这份清单聚焦于那些“低成本、高收益”的加固点,旨在用最小的改动,消除最普遍的风险。真正的安全防御是一个纵深体系,从网络、主机、应用到代码、数据、人员,每一层都不可或缺。但对于使用若依框架的开发者而言,先把这五个“地基”打牢,已经能抵御绝大多数自动化攻击和常见的手工测试了。记住,默认不代表安全,方便不等于可靠。每一次不经意的“沿用默认”,都可能为未来埋下一颗雷。