版本号:
2.2.1 (master)
问题描述:
在组织管理模块SysOrgRestController中,多个接口存在多租户隔离缺失问题,攻击者在具备基础权限的情况下,可通过构造请求参数实现跨租户的数据写入、修改及删除,导致权限绕过。
insert接口
在新增组织机构数据时,系统未对请求体中的tenantId与parentId字段进行有效校验或绑定。当创建根节点组织时,后端会直接使用客户端传入的tenantId进行数据写入;当指定父节点组织时,后端会通过父节点自动设置tenantId。攻击者可通过篡改这些字段,将数据插入到目标租户中,实现跨租户写入。
update接口
更新接口同样存在租户字段未受保护的问题。攻击者可以通过篡改请求体中的字段,将自身租户下的数据迁移至其他租户,实现跨租户写操作。
del接口
删除操作仅基于传入的id执行,但未校验该资源是否属于当前用户所在租户。攻击者可通过指定其他租户的id,直接删除对应数据,实现跨租户删除。
综上,SysOrgRestController中,未在后端对租户信息进行绑定与归属校验,直接信任前端传入的字段,导致多租户隔离机制失效,影像数据完整性与隔离性。
漏洞分析:
以insert接口为例,在Controller层中,接口接收前端传入的SysOrgModel对象,但未对其中字段进行校验,然后直接将数据传入Service层。
// 如果新增的是 根节点数据 则需要验证权限
if(null != model && TreeBuildUtil.DEF_PARENT_ID.equals(model.getParentId())){
UserModel currUser = UserUtil.getUser();
// 如果不是超级管理员 和 租户管理员
if(!StringUtils.equals(UserUtil.SUPER_ADMIN, currUser.getUsername()) &&
!TenantUtil.SUPER_ADMIN_TENANT_ID.equals(currUser.getTenantId()) ){
RoleModel defRoleByUserId = UserUtil.getUserDefRoleByUserId(currUser.getId());
if(null == defRoleByUserId ||
StringUtils.isEmpty(defRoleByUserId.getDataScope()) ||
!DictType.DATA_SCOPE_ALL.getValue().equals(defRoleByUserId.getDataScope())){
// 无组织机构新增权限
throw new ServiceException(SystemMsg.EXCEPTION_ORG_NOT_PERMISSION);
}
}
}
// 调用新增方法
IService.insert(model);
在Service层insert方法中,系统对租户信息的处理依赖如下逻辑:
// 如果上级ID 为空 则默认为 0
if(StringUtils.isEmpty(model.getParentId()) || TOP_PARENT_ID.equals(model.getParentId())){
model.setParentId(TOP_PARENT_ID);
model.setParentIds(TOP_PARENT_ID);
}
// 如果上级ID不为空 且 不等于顶级ID
if(StringUtils.isNotEmpty(model.getParentId()) &&
!TOP_PARENT_ID.equals(model.getParentId())
){
SysOrgModel sysOrgModel = super.get(model.getParentId());
// 下级沿用上级租户ID
model.setTenantId(sysOrgModel.getTenantId());
// 下级沿用上级ParentIds
model.setParentIds(
StrUtil.appendIfMissing(
sysOrgModel.getParentIds(), DELIMITER) +
sysOrgModel.getId());
}
当创建根节点组织时,tenantId完全来自前端输入,并直接参与后续数据写入;而存在父节点情况下,后端未校验parentId是否属于当前用户所在租户,直接继承父节点租户。
对比分析:
在用户管理模块的实现中(如UserRestController.insert),系统对tenantId进行了显式的权限控制,在无权限情况下强制清空客户端传入的tenantId:
// 判断用户是否有 修改租户的能力 (超级管理员除外)
if(StringUtils.isNotEmpty(model.getTenantId())){
// 如果没有租户修改能力 则清空对应字段
if(!UserUtil.isHasUpdateTenantPerms(UserUtil.getUser())){
model.setTenantId(null);
model.setIzTenantAdmin(null);
model.setEnableSwitchTenant(DictType.NO_YES_NO.getValue());
}
}
补充说明:
update 接口:逻辑与 insert 类似,后端直接使用了前端传入的 tenantId,从而实现跨租户数据修改。
delete 接口:删除操作基于 id 执行,未校验该资源是否属于当前租户,也未附加租户条件,攻击者可通过指定其他租户的 id 实现跨租户删除,属于典型 IDOR 漏洞。
漏洞复现:
以insert接口为例,使用默认导入的sql文件,t123456(攻击者)和tenant(目标)用户位于两个不同租户中。tenant所在租户id为1,当前组织如下:

攻击者通过构造请求体,并篡改tenantId,实现越权写入操作:

此外,通过篡改parentId,也可以实现跨租户子机构添加操作:


版本号:
2.2.1 (master)
问题描述:
在组织管理模块
SysOrgRestController中,多个接口存在多租户隔离缺失问题,攻击者在具备基础权限的情况下,可通过构造请求参数实现跨租户的数据写入、修改及删除,导致权限绕过。insert接口在新增组织机构数据时,系统未对请求体中的
tenantId与parentId字段进行有效校验或绑定。当创建根节点组织时,后端会直接使用客户端传入的tenantId进行数据写入;当指定父节点组织时,后端会通过父节点自动设置tenantId。攻击者可通过篡改这些字段,将数据插入到目标租户中,实现跨租户写入。update接口更新接口同样存在租户字段未受保护的问题。攻击者可以通过篡改请求体中的字段,将自身租户下的数据迁移至其他租户,实现跨租户写操作。
del接口删除操作仅基于传入的
id执行,但未校验该资源是否属于当前用户所在租户。攻击者可通过指定其他租户的id,直接删除对应数据,实现跨租户删除。综上,
SysOrgRestController中,未在后端对租户信息进行绑定与归属校验,直接信任前端传入的字段,导致多租户隔离机制失效,影像数据完整性与隔离性。漏洞分析:
以
insert接口为例,在Controller层中,接口接收前端传入的SysOrgModel对象,但未对其中字段进行校验,然后直接将数据传入Service层。在Service层
insert方法中,系统对租户信息的处理依赖如下逻辑:当创建根节点组织时,
tenantId完全来自前端输入,并直接参与后续数据写入;而存在父节点情况下,后端未校验parentId是否属于当前用户所在租户,直接继承父节点租户。对比分析:
在用户管理模块的实现中(如
UserRestController.insert),系统对tenantId进行了显式的权限控制,在无权限情况下强制清空客户端传入的tenantId:补充说明:
update接口:逻辑与insert类似,后端直接使用了前端传入的tenantId,从而实现跨租户数据修改。delete接口:删除操作基于id执行,未校验该资源是否属于当前租户,也未附加租户条件,攻击者可通过指定其他租户的id实现跨租户删除,属于典型 IDOR 漏洞。漏洞复现:
以




insert接口为例,使用默认导入的sql文件,t123456(攻击者)和tenant(目标)用户位于两个不同租户中。tenant所在租户id为1,当前组织如下:攻击者通过构造请求体,并篡改
tenantId,实现越权写入操作:此外,通过篡改
parentId,也可以实现跨租户子机构添加操作: