RuoYi-Vue 安全合规改造:从风险诊断到等保三级落地实践
问题诊断:企业级应用的安全痛点剖析
在数字化转型加速的今天,企业信息系统面临着日益复杂的安全威胁。基于SpringBoot与Vue构建的RuoYi-Vue权限管理系统作为众多企业的基础支撑平台,其安全合规性直接关系到核心业务数据的保护。通过对现有系统的深度审计,我们发现以下关键安全风险点:
身份认证机制存在短板,默认2小时的JWT令牌有效期过长,且缺乏动态刷新机制;权限控制颗粒度不足,按钮级操作权限未完全独立配置;敏感数据在传输和存储环节未进行严格加密;审计日志留存周期不足6个月,难以满足等保三级的追溯要求;定时任务缺乏精细化的权限校验和操作审计。这些隐患如同不设防的门户,随时可能导致数据泄露、越权操作等严重安全事件。
解决方案:构建全方位安全防护体系
身份认证与访问控制强化
风险点识别(风险等级:高,实施优先级:P0)
- 密码策略强度不足,易遭受暴力破解
- JWT令牌有效期过长,增加被盗用风险
- 缺乏会话超时自动登出机制
技术实现
路径一:密码策略增强 在用户管理服务实现类中添加密码强度检测逻辑,确保密码复杂度符合等保要求:
// 文件路径:ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
private void validatePasswordStrength(String password) {
// 密码长度至少8位
if (password.length() < 8) {
throw new UserException("密码长度不能少于8位");
}
// 包含大小写字母、数字及特殊符号
if (!password.matches("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$")) {
throw new UserException("密码必须包含大小写字母、数字和特殊符号");
}
}
路径二:会话管理优化 扩展登录用户模型,实现令牌自动刷新机制:
// 文件路径:ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
private Long tokenExpireTime;
// 检查是否需要刷新令牌
public boolean isTokenExpiring() {
long currentTime = System.currentTimeMillis();
// 剩余5分钟时触发刷新
return (tokenExpireTime - currentTime) < 300000;
}
在令牌服务中添加刷新逻辑:
// 文件路径:ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java
public String refreshToken(LoginUser loginUser) {
if (loginUser.isTokenExpiring()) {
// 生成新令牌
String newToken = createToken(loginUser);
// 更新缓存
redisCache.setCacheObject(loginUser.getTokenKey(), loginUser, getExpireTime(), TimeUnit.MINUTES);
return newToken;
}
return loginUser.getToken();
}
效果验证
- 尝试创建不符合复杂度要求的密码,系统应拒绝并提示具体规则
- 令牌有效期设置为30分钟,闲置25分钟后执行操作应自动刷新令牌
- 超过30分钟未操作,系统应提示会话超时并强制登出
行业最佳实践
金融行业通常采用"双因素认证+动态令牌"机制,如银行系统在密码基础上增加U盾或手机验证码。建议对管理员账户额外启用二次验证,可集成企业微信或钉钉的扫码登录功能。
权限管理精细化改造
风险点识别(风险等级:中,实施优先级:P1)
- 权限控制未细化到按钮级别
- 数据权限分离不彻底,存在越权访问风险
- 缺乏权限继承机制,角色管理复杂
技术实现
路径一:按钮级权限控制 在角色管理页面添加按钮权限配置功能:
<!-- 文件路径:ruoyi-ui/src/views/system/role/index.vue -->
<el-table-column label="操作权限">
<template slot-scope="scope">
<el-popover
placement="right"
width="400"
trigger="click">
<el-tree
:data="buttonPermissions"
show-checkbox
node-key="id"
:default-checked-keys="scope.row.buttonPerms"
@check-change="handleButtonPermChange(scope.row, $event)">
</el-tree>
<el-button slot="reference" type="text" size="small">配置</el-button>
</el-popover>
</template>
</el-table-column>
路径二:数据权限动态控制 增强数据权限切面,支持更细粒度的权限控制:
// 文件路径:ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java
private String getScopeSql(SysUser user) {
StringBuilder sqlString = new StringBuilder();
// 数据权限范围:全部、自定义、本部门、本部门及以下、仅本人
if (!user.isAdmin()) {
sqlString.append(" AND (");
// 自定义数据权限
List<Long> deptIds = user.getDeptIds();
if (CollUtil.isNotEmpty(deptIds)) {
sqlString.append(" d.dept_id IN (").append(StringUtils.join(deptIds, ",")).append(")");
}
// 本部门数据权限
if (user.getDataScope().equals("1")) {
sqlString.append(" OR d.dept_id = ").append(user.getDeptId());
}
// 本部门及以下数据权限
if (user.getDataScope().equals("2")) {
sqlString.append(" OR d.dept_id IN (SELECT dept_id FROM sys_dept WHERE ancestors LIKE '%" + user.getDeptId() + "%')");
}
// 仅本人数据权限
if (user.getDataScope().equals("3")) {
sqlString.append(" OR u.user_id = ").append(user.getUserId());
}
sqlString.append(")");
}
return sqlString.toString();
}
效果验证
- 创建测试角色并配置部分按钮权限,使用该角色登录系统,验证未授权按钮是否隐藏
- 配置不同数据权限范围的用户,验证其只能访问权限范围内的数据
- 创建子角色继承父角色权限,验证权限继承功能是否正常
行业最佳实践
大型企业通常采用"RBAC+ABAC"混合权限模型,即基于角色的访问控制结合基于属性的访问控制。例如电商平台可根据用户等级、订单金额等属性动态调整操作权限,建议在后续版本中引入此机制。
安全审计与日志管理
风险点识别(风险等级:高,实施优先级:P0)
- 审计日志记录不完整,关键操作缺乏记录
- 日志存储周期不足,无法满足等保6个月要求
- 缺乏日志防篡改机制
技术实现
路径一:全面日志采集 增强操作日志注解,确保所有关键操作被记录:
// 文件路径:ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
/** 模块 */
String title() default "";
/** 功能 */
BusinessType businessType() default BusinessType.OTHER;
/** 是否保存请求的参数 */
boolean saveRequestData() default true;
/** 是否保存响应的参数 */
boolean saveResponseData() default true;
/** 操作人类别 */
OperatorType operatorType() default OperatorType.MANAGE;
/** 是否异步记录日志 */
boolean isAsync() default false;
}
路径二:日志安全存储 实现日志定时备份功能:
// 文件路径:ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobServiceImpl.java
@Scheduled(cron = "0 0 1 * * ?") // 每天凌晨1点执行
public void backupOperLog() {
// 创建备份表
String backupTableName = "sys_oper_log_" + DateUtils.format(new Date(), "yyyyMMdd");
String createTableSql = "CREATE TABLE " + backupTableName + " LIKE sys_oper_log";
jdbcTemplate.execute(createTableSql);
// 迁移数据
String insertSql = "INSERT INTO " + backupTableName + " SELECT * FROM sys_oper_log WHERE oper_time < DATE_SUB(NOW(), INTERVAL 1 DAY)";
jdbcTemplate.execute(insertSql);
// 删除原表数据
String deleteSql = "DELETE FROM sys_oper_log WHERE oper_time < DATE_SUB(NOW(), INTERVAL 1 DAY)";
jdbcTemplate.execute(deleteSql);
// 保留180天备份
String dropSql = "DROP TABLE IF EXISTS sys_oper_log_" + DateUtils.format(DateUtils.addDays(new Date(), -180), "yyyyMMdd");
jdbcTemplate.execute(dropSql);
}
效果验证
- 执行关键操作(如用户创建、角色授权)后,检查操作日志是否完整记录
- 验证日志备份功能是否每天执行,备份文件是否保留180天
- 尝试修改历史日志记录,验证系统是否能检测并告警
行业最佳实践
金融行业普遍采用"三员分立"制度(系统管理员、安全管理员、审计管理员),日志管理权限严格分离。建议在系统中实现审计日志的只读权限控制,确保日志数据的完整性和真实性。
敏感数据保护措施
风险点识别(风险等级:高,实施优先级:P0)
- 敏感数据传输未加密
- 存储敏感信息未加密
- 缺乏数据脱敏展示机制
技术实现
路径一:传输加密(HTTPS配置)
# 文件路径:ruoyi-admin/src/main/resources/application.yml
server:
port: 443
ssl:
enabled: true
key-store: classpath:keystore.p12
key-store-password: RuoYi@2023
key-store-type: PKCS12
key-alias: ruoyi
protocol: TLSv1.3
ciphers: TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256,TLS_AES_128_GCM_SHA256
路径二:存储加密(AES与国密SM4对比实现)
AES加密实现:
// 文件路径:ruoyi-common/src/main/java/com/ruoyi/common/utils/security/SecurityUtils.java
public static String aesEncrypt(String content, String key) {
try {
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, new byte[12]);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, gcmParameterSpec);
byte[] encrypted = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
return Base64.encodeBase64String(encrypted);
} catch (Exception e) {
throw new UtilException("AES加密失败", e);
}
}
国密SM4加密实现:
// 文件路径:ruoyi-common/src/main/java/com/ruoyi/common/utils/security/SecurityUtils.java
public static String sm4Encrypt(String content, String key) {
try {
SM4Engine engine = new SM4Engine(SM4Engine.MODE_CBC);
KeyParameter keyParameter = new KeyParameter(key.getBytes());
engine.init(true, keyParameter);
byte[] srcData = content.getBytes(StandardCharsets.UTF_8);
byte[] cipherData = new byte[engine.getOutputSize(srcData.length)];
int len = engine.processBytes(srcData, 0, srcData.length, cipherData, 0);
engine.doFinal(cipherData, len);
return Base64.encodeBase64String(cipherData);
} catch (Exception e) {
throw new UtilException("SM4加密失败", e);
}
}
效果验证
- 访问系统验证是否自动跳转至HTTPS
- 检查数据库中敏感字段(如身份证号、手机号)是否加密存储
- 在前端页面验证敏感信息是否脱敏展示(如手机号显示为138****5678)
行业最佳实践
金融和政务领域普遍要求使用国密算法(SM2/SM3/SM4)进行数据加密。建议对涉及国家秘密、商业秘密的系统优先采用国密算法,普通企业可根据合规要求选择AES或国密算法。
定时任务安全管控
风险点识别(风险等级:中,实施优先级:P1)
- 定时任务缺乏权限控制
- 任务执行过程无审计记录
- 任务异常缺乏告警机制
技术实现
路径一:任务权限控制
// 文件路径:ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java
private String permission; // 任务操作权限标识
// 文件路径:ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobServiceImpl.java
@Override
public void validateJobPermission(SysJob job) {
if (StringUtils.isNotEmpty(job.getPermission())
&& !SecurityUtils.hasPermi(job.getPermission())) {
throw new AccessDeniedException("无权限操作定时任务:" + job.getJobName());
}
}
路径二:任务执行审计
// 文件路径:ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/SysJobLogMapper.java
public interface SysJobLogMapper {
/**
* 新增任务日志
*/
int insertJobLog(SysJobLog jobLog);
/**
* 查询任务日志详情
*/
SysJobLog selectJobLogById(Long jobLogId);
/**
* 查询任务日志列表
*/
List<SysJobLog> selectJobLogList(SysJobLog jobLog);
}
效果验证
- 使用无权限用户尝试执行定时任务,验证是否被拒绝
- 执行定时任务后,检查任务日志是否完整记录执行信息
- 故意配置错误的任务参数,验证系统是否记录异常信息并告警
行业最佳实践
大型企业通常采用专门的任务调度平台(如XXL-Job、Elastic-Job)管理定时任务,提供更完善的权限控制、监控告警和容错机制。建议对核心业务定时任务考虑接入专业调度平台。
实施验证:构建安全合规的闭环体系
实施计划
第一阶段:准备阶段(1周)
- 责任人:系统架构师
- 任务1:梳理现有系统权限体系,输出权限矩阵表
- 任务2:制定详细改造计划和测试方案
- 任务3:准备加密所需的密钥和证书
第二阶段:核心改造(3周)
- 责任人:后端开发工程师、前端开发工程师
- 任务1:身份认证与权限控制模块改造(1周)
- 任务2:日志审计与敏感数据保护改造(1周)
- 任务3:定时任务安全管控改造(0.5周)
- 任务4:系统集成与联调(0.5周)
第三阶段:测试验证(2周)
- 责任人:测试工程师、安全工程师
- 任务1:功能测试(0.5周)
- 任务2:安全渗透测试(1周)
- 任务3:性能测试与优化(0.5周)
第四阶段:部署上线(1周)
- 责任人:运维工程师
- 任务1:生产环境准备与配置
- 任务2:数据迁移与系统部署
- 任务3:上线后监控与问题修复
常见问题排查
问题1:令牌刷新机制失效
- 现象:用户操作过程中突然提示会话超时
- 排查步骤:
- 检查Redis缓存中登录用户信息是否过期
- 验证前端请求是否正确携带令牌
- 查看令牌刷新逻辑是否正确处理异常情况
- 解决方案:调整令牌刷新时机,确保在令牌过期前5分钟触发刷新
问题2:数据权限过滤异常
- 现象:用户可以看到无权限的数据
- 排查步骤:
- 检查用户数据权限配置是否正确
- 调试DataScopeAspect查看生成的SQL条件是否正确
- 验证数据库中部门关系数据是否准确
- 解决方案:修复数据权限SQL生成逻辑,增加权限过滤日志输出
问题3:敏感数据加密后查询异常
- 现象:加密存储后无法通过明文条件查询数据
- 排查步骤:
- 检查查询条件是否进行了正确加密
- 验证加密算法前后一致性
- 确认数据库字段长度是否足够存储加密后的数据
- 解决方案:实现基于加密字段的模糊查询功能,或采用部分加密方案
问题4:定时任务执行日志不完整
- 现象:部分定时任务执行后无日志记录
- 排查步骤:
- 检查任务执行是否抛出未捕获异常
- 验证日志记录逻辑是否在所有执行路径都被调用
- 查看数据库连接是否正常
- 解决方案:增加全局异常捕获,确保日志记录逻辑可靠执行
问题5:HTTPS配置后系统无法访问
- 现象:配置HTTPS后浏览器提示证书错误或无法连接
- 排查步骤:
- 检查证书是否正确配置
- 验证端口是否开放且未被占用
- 确认SSL协议和密码套件是否配置正确
- 解决方案:使用正规CA签发的证书,确保服务器时间与证书有效期匹配
安全合规检查清单
-
身份认证
- [ ] 密码长度不少于8位,包含大小写字母、数字和特殊符号
- [ ] 实现90天密码定期更换机制
- [ ] 禁止使用前5次历史密码
- [ ] JWT令牌有效期设置为30分钟
- [ ] 实现令牌自动刷新机制
-
访问控制
- [ ] 所有操作按钮配置独立权限标识
- [ ] 实现基于角色的数据权限控制
- [ ] 支持数据权限范围:全部、自定义、本部门、本部门及以下、仅本人
- [ ] 关键操作需二次确认
-
安全审计
- [ ] 记录所有用户关键操作,包含操作人、IP、时间、参数、结果
- [ ] 审计日志保存至少180天
- [ ] 实现日志防篡改机制
- [ ] 敏感操作添加双人复核机制
-
数据保护
- [ ] 所有HTTP通信采用HTTPS加密
- [ ] 敏感数据存储采用AES或国密SM4加密
- [ ] 前端展示敏感信息进行脱敏处理
- [ ] 实现数据备份与恢复机制
-
定时任务
- [ ] 定时任务配置独立操作权限
- [ ] 记录任务执行日志,包含执行人、参数、结果
- [ ] 任务异常自动告警
- [ ] 关键任务执行前需权限验证
通过以上改造,RuoYi-Vue系统将全面满足《信息安全技术 网络安全等级保护基本要求》(GB/T 22239-2019)三级标准,构建起从身份认证、权限控制到数据保护的完整安全防线。建议企业建立常态化安全合规检查机制,每季度进行一次安全评估,确保系统安全状态持续符合要求。
GLM-5智谱 AI 正式发布 GLM-5,旨在应对复杂系统工程和长时域智能体任务。Jinja00
GLM-5.1GLM-5.1是智谱迄今最智能的旗舰模型,也是目前全球最强的开源模型。GLM-5.1大大提高了代码能力,在完成长程任务方面提升尤为显著。和此前分钟级交互的模型不同,它能够在一次任务中独立、持续工作超过8小时,期间自主规划、执行、自我进化,最终交付完整的工程级成果。Jinja00
LongCat-AudioDiT-1BLongCat-AudioDiT 是一款基于扩散模型的文本转语音(TTS)模型,代表了当前该领域的最高水平(SOTA),它直接在波形潜空间中进行操作。00- QQwen3.5-397B-A17BQwen3.5 实现了重大飞跃,整合了多模态学习、架构效率、强化学习规模以及全球可访问性等方面的突破性进展,旨在为开发者和企业赋予前所未有的能力与效率。Jinja00
HY-Embodied-0.5这是一套专为现实世界具身智能打造的基础模型。该系列模型采用创新的混合Transformer(Mixture-of-Transformers, MoT) 架构,通过潜在令牌实现模态特异性计算,显著提升了细粒度感知能力。Jinja00
FreeSql功能强大的对象关系映射(O/RM)组件,支持 .NET Core 2.1+、.NET Framework 4.0+、Xamarin 以及 AOT。C#00
