diff --git a/opsli-base-support/opsli-core/pom.xml b/opsli-base-support/opsli-core/pom.xml
index 53d2ae18..91dd1cc5 100644
--- a/opsli-base-support/opsli-core/pom.xml
+++ b/opsli-base-support/opsli-core/pom.xml
@@ -111,6 +111,12 @@
mybatis-plus-spring-boot3-starter
+
+
+ com.baomidou
+ mybatis-plus-jsqlparser
+
+
com.github.pagehelper
pagehelper-spring-boot-starter
diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/autoconfigure/conf/MyBatisPlusConfig.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/autoconfigure/conf/MyBatisPlusConfig.java
index 3b6c9491..19f9cdd1 100644
--- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/autoconfigure/conf/MyBatisPlusConfig.java
+++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/autoconfigure/conf/MyBatisPlusConfig.java
@@ -16,6 +16,7 @@
package org.opsli.core.autoconfigure.conf;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
@@ -49,8 +50,9 @@ public class MyBatisPlusConfig {
// 乐观锁
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
- // 防止全表更新与删除插件
- //mybatisPlusInterceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
+ // 防止全表更新与删除插件 - 安全加固
+ // 拦截无 WHERE 条件的 UPDATE/DELETE,避免因业务 bug 或 SQL 注入导致整表数据被清空
+ mybatisPlusInterceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return mybatisPlusInterceptor;
}
diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserUtil.java
index 4795c824..21f13358 100644
--- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserUtil.java
+++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserUtil.java
@@ -42,6 +42,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Component;
import java.util.List;
@@ -747,6 +748,59 @@ public class UserUtil {
userAllPermsByUserId.contains(PERMS_TENANT);
}
+ /**
+ * 校验当前登录人是否有权访问目标 userId 的数据 - 修复越权漏洞
+ *
+ * 规则:
+ *
+ * - 查自己 → 放行
+ * - 当前用户是超级管理员 → 放行
+ * - 目标用户是超级管理员 → 仅超管可访问(普通人拦截)
+ * - 跨租户访问 → 拦截
+ * - 同租户且目标非超管 → 放行
+ *
+ * 不满足放行条件的一律抛 {@link AccessDeniedException},由统一异常处理返回无权访问
+ *
+ * @param targetUserId 目标用户ID
+ */
+ public static void checkUserAccess(String targetUserId) {
+ // 判断 工具类是否初始化完成
+ ThrowExceptionUtil.isThrowException(!IS_INIT,
+ CoreMsg.OTHER_EXCEPTION_UTILS_INIT);
+
+ if (StringUtils.isBlank(targetUserId)) {
+ throw new AccessDeniedException("参数错误");
+ }
+
+ // getUser() 失败会直接抛 TokenException,此处不会返回 null
+ UserModel currUser = getUser();
+
+ // 1) 查自己:放行
+ if (StringUtils.equals(currUser.getId(), targetUserId)) {
+ return;
+ }
+
+ // 2) 当前用户是超级管理员:放行
+ if (StringUtils.equals(SUPER_ADMIN, currUser.getUsername())) {
+ return;
+ }
+
+ UserModel targetUser = getUser(targetUserId);
+ if (targetUser == null) {
+ throw new AccessDeniedException("用户不存在");
+ }
+
+ // 3) 非超管不能查超级管理员的数据
+ if (StringUtils.equals(SUPER_ADMIN, targetUser.getUsername())) {
+ throw new AccessDeniedException("无权访问");
+ }
+
+ // 4) 非超管不能跨租户访问
+ if (!StringUtils.equals(currUser.getTenantId(), targetUser.getTenantId())) {
+ throw new AccessDeniedException("无权访问");
+ }
+ }
+
// =====================================
/**
diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/dict/web/DictRestController.java b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/dict/web/DictRestController.java
index 25857e32..4e8359f8 100644
--- a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/dict/web/DictRestController.java
+++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/dict/web/DictRestController.java
@@ -69,6 +69,7 @@ public class DictRestController extends BaseRestController get(DictModel model) {
model = IService.get(model);
@@ -83,6 +84,7 @@ public class DictRestController extends BaseRestController findPage(Integer pageNo, Integer pageSize, HttpServletRequest request) {
@@ -173,7 +175,7 @@ public class DictRestController extends BaseRestController> findAllOptions() {
+ // 修复 越权漏洞 - 系统参数属于平台级全局配置(含阿里云 AccessKey / 邮箱配置 / 非对称加密公钥等),
+ // 仅允许超级管理员访问,防止租户管理员跨租户读取敏感配置
+ UserModel currUser = UserUtil.getUser();
+ if (!StringUtils.equals(UserUtil.SUPER_ADMIN, currUser.getUsername())) {
+ throw new AccessDeniedException("无权访问");
+ }
+
QueryWrapper queryWrapper = new QueryWrapper<>();
// 查询内置数据
queryWrapper.eq("iz_lock", DictType.NO_YES_YES.getValue());
diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/role/web/RoleRestController.java b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/role/web/RoleRestController.java
index 7246a8b7..1b9c551b 100644
--- a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/role/web/RoleRestController.java
+++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/role/web/RoleRestController.java
@@ -74,7 +74,7 @@ public class RoleRestController extends BaseRestController findPage(Integer pageNo, Integer pageSize, HttpServletRequest request) {
diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/tenant/web/TenantRestController.java b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/tenant/web/TenantRestController.java
index c6aafa46..240ab309 100644
--- a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/tenant/web/TenantRestController.java
+++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/tenant/web/TenantRestController.java
@@ -99,7 +99,7 @@ public class TenantRestController extends BaseRestController findPage(Integer pageNo, Integer pageSize, HttpServletRequest request) {
diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/service/impl/UserServiceImpl.java b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/service/impl/UserServiceImpl.java
index 0b7b95fe..0b675f10 100644
--- a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/service/impl/UserServiceImpl.java
+++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/service/impl/UserServiceImpl.java
@@ -543,6 +543,9 @@ public class UserServiceImpl extends CrudServiceImpl getInfoById(String userId) {
+ // 修复 越权漏洞 - 校验当前登录人是否有权访问目标 userId 的数据
+ // (内部方法 getInfo() 通过 this.getInfoById(...) 调用时,
+ // Spring AOP 对 this 调用不生效,@PreAuthorize 不会触发;
+ // checkUserAccess 查自己时直接放行,保持既有行为)
+ UserUtil.checkUserAccess(userId);
+
UserModel currUser = UserUtil.getUserBySource(userId);
if(currUser == null){
throw new TokenException(TokenMsg.EXCEPTION_TOKEN_LOSE_EFFICACY);
@@ -159,8 +166,15 @@ public class UserRestController extends BaseRestController getOrgByUserId(String userId) {
+ // 修复 越权漏洞 - 校验当前登录人是否有权访问目标 userId 的数据
+ // (内部方法 getOrg() 通过 this.getOrgByUserId(user.getId()) 调用时,
+ // Spring AOP 对 this 调用不生效,@PreAuthorize 不会触发;
+ // checkUserAccess 查自己时直接放行,保持既有行为)
+ UserUtil.checkUserAccess(userId);
+
List orgListByUserId = UserUtil.getOrgListByUserId(userId);
return ResultWrapper.getSuccessResultWrapper(orgListByUserId);
}
@@ -171,8 +185,12 @@ public class UserRestController extends BaseRestController> getRoleIdsByUserId(String userId) {
+ // 修复 越权漏洞 - 校验当前登录人是否有权访问目标 userId 的数据
+ UserUtil.checkUserAccess(userId);
+
List roleIdList = iUserRoleRefService.getRoleIdList(userId);
return ResultWrapper.getSuccessResultWrapper(roleIdList);
}
@@ -392,6 +410,9 @@ public class UserRestController extends BaseRestController getRoles(String userId) {
+ // 修复 越权漏洞 - 校验当前登录人是否有权访问目标 userId 的数据
+ UserUtil.checkUserAccess(userId);
List roleIdList = iUserRoleRefService.getRoleIdList(userId);
String defRoleId = iUserRoleRefService.getDefRoleId(userId);
@@ -91,6 +94,9 @@ public class UserRoleRefRestController implements UserRoleRefApi {
// 演示模式 不允许操作
this.demoError();
+ // 修复越权漏洞 - 校验当前登录人是否有权为目标 userId 设置角色
+ UserUtil.checkUserAccess(model.getUserId());
+
boolean ret = iUserRoleRefService.setRoles(model);
if(ret){
return ResultWrapper.getSuccessResultWrapper();
diff --git a/pom.xml b/pom.xml
index 41e2498d..4c771181 100644
--- a/pom.xml
+++ b/pom.xml
@@ -148,6 +148,13 @@
${mybatis-plus.version}
+
+
+ com.baomidou
+ mybatis-plus-jsqlparser
+ ${mybatis-plus.version}
+
+
com.github.pagehelper
pagehelper-spring-boot-starter
@@ -213,11 +220,15 @@
org.springframework.boot
spring-boot-starter-aop
-
+
+
+
+
org.springframework.boot