从 mall 0day IDOR 挖掘看 Spring 权限管理
字数 1704 2025-09-01 11:25:54

Spring权限管理与IDOR漏洞挖掘实战指南

一、Spring权限管理概述

在企业级应用中,权限控制是核心安全环节。Spring生态提供了丰富的权限管理手段,主要分为两类:

  1. 垂直权限(Vertical Access Control):控制"角色等级"对资源或操作的访问
  2. 水平权限(Horizontal Access Control):防止用户操作自己无权访问的同级资源

二、垂直权限实现方式

1. HandlerInterceptor拦截器

在Spring MVC中,可以通过HandlerInterceptorpreHandle()方法在请求到达Controller前进行权限校验:

public class AuthInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, 
                           HttpServletResponse response, 
                           Object handler) throws Exception {
        // 权限校验逻辑
        if(!hasPermission(request)){
            response.sendError(403);
            return false;
        }
        return true;
    }
}

优点:逻辑集中,可统一管理
缺点:复杂规则需要手写,维护成本高

2. Spring Security方案

URL级权限:通过配置URL与角色映射控制访问

http.authorizeRequests()
    .antMatchers("/admin/**").hasRole("ADMIN")
    .antMatchers("/user/**").hasRole("USER");

方法级注解

  • @PreAuthorize:方法执行前校验
  • @PostAuthorize:方法执行后校验(可基于返回值判断)
@PreAuthorize("hasRole('ADMIN') or hasPermission(#id, 'read')")
public String sensitiveMethod(Long id) {
    // ...
}

自定义PermissionEvaluator:实现复杂业务规则

public class CustomPermissionEvaluator implements PermissionEvaluator {
    @Override
    public boolean hasPermission(Authentication auth, Object target, Object permission) {
        // 自定义权限判断逻辑
    }
}

3. Apache Shiro方案

支持细粒度权限控制,如"document:read:123"表示对ID为123的文档有读权限

@RequiresPermissions("document:read:#documentId")
public Document getDocument(Long documentId) {
    // ...
}

4. 自定义注解+AOP

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ResourcePermission {
    String resourceType();
    String permission();
}

@Aspect
@Component
public class PermissionAspect {
    @Around("@annotation(resourcePermission)")
    public Object checkPermission(ProceedingJoinPoint joinPoint, 
                                ResourcePermission resourcePermission) {
        // 权限校验逻辑
        if(!hasPermission(resourcePermission.resourceType(), 
                        resourcePermission.permission())){
            throw new AccessDeniedException("无权限");
        }
        return joinPoint.proceed();
    }
}

三、水平权限实现方式

水平权限检查依赖资源归属,通常需要分散在业务逻辑或数据库查询层。

1. 数据库层过滤

// 查询时自动添加用户ID条件
@Query("SELECT o FROM Order o WHERE o.id = ?1 AND o.userId = ?2")
Order findByIdAndUserId(Long id, Long userId);

2. 方法层判断

public Order getOrder(Long orderId) {
    Order order = orderRepository.findById(orderId);
    if(order == null || !order.getUserId().equals(getCurrentUserId())){
        throw new AccessDeniedException("无权访问该订单");
    }
    return order;
}

3. AOP+注解封装

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ResourceOwner {
    String idParam() default "id";
}

@Aspect
@Component
public class ResourceOwnerAspect {
    @Around("@annotation(resourceOwner)")
    public Object checkOwner(ProceedingJoinPoint joinPoint, 
                           ResourceOwner resourceOwner) {
        // 获取参数中的资源ID
        Long resourceId = getResourceId(joinPoint, resourceOwner.idParam());
        // 验证当前用户是否为资源所有者
        if(!isOwner(resourceId)){
            throw new AccessDeniedException("无权操作该资源");
        }
        return joinPoint.proceed();
    }
}

4. 数据库行级安全(RLS)

PostgreSQL等数据库支持行级安全策略:

CREATE POLICY order_owner_policy ON orders
    USING (user_id = current_user_id());
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;

四、IDOR漏洞挖掘实战

以mall项目为例,分析其权限管理实现和漏洞挖掘过程。

1. 垂直权限分析

mall的Security模块中,DynamicSecurityFilter继承了AbstractSecurityInterceptor

public class DynamicSecurityFilter extends AbstractSecurityInterceptor implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, 
                       ServletResponse servletResponse, 
                       FilterChain filterChain) throws IOException, ServletException {
        // 权限校验逻辑
    }
}

核心权限决策流程:

  1. AccessDecisionManager.decide()方法调用
  2. 通过DynamicSecurityMetadataSource.getAttributes()获取权限规则
  3. 规则通过dynamicSecurityService.loadDataSource()加载
  4. 最终从数据库ums_resource表读取URL-角色映射规则

结论:垂直权限控制完善,难以构造越权。

2. 水平权限漏洞挖掘

漏洞一:订单取消越权

接口/order/cancelUserOrder

问题代码

@PostMapping("/cancelUserOrder")
public CommonResult cancelUserOrder(@RequestParam Long orderId) {
    return portalOrderService.cancelOrder(orderId);
}

// portalOrderService.cancelOrder实现
public CommonResult cancelOrder(Long orderId) {
    // 直接操作订单,未校验订单归属
    orderMapper.updateStatus(orderId, 4); // 4表示已取消
    return CommonResult.success(null);
}

利用步骤

  1. 注册新用户(无任何订单)
  2. 从数据库选择其他用户的订单ID(如状态为未支付的73号订单)
  3. 向接口发送取消请求:
    POST /order/cancelUserOrder
    Content-Type: application/x-www-form-urlencoded
    
    orderId=73
    
  4. 数据库检查确认订单状态被修改

漏洞二:支付状态篡改

接口/order/paySuccess

问题代码

@PostMapping("/paySuccess")
public CommonResult paySuccess(@RequestParam Long orderId, 
                             @RequestParam Integer payType) {
    return portalOrderService.paySuccess(orderId, payType);
}

// portalOrderService.paySuccess实现
public CommonResult paySuccess(Long orderId, Integer payType) {
    // 直接修改订单状态为已支付,无任何校验
    orderMapper.updateStatus(orderId, 1); // 1表示待发货
    return CommonResult.success(null);
}

严重性

  1. 实现0元购:未支付订单直接改为已支付
  2. 平台攻击:枚举修改大量订单状态,导致交易系统瘫痪

利用步骤

  1. 选择未支付订单(如73号)
  2. 发送支付成功请求:
    POST /order/paySuccess
    Content-Type: application/x-www-form-urlencoded
    
    orderId=73&payType=1
    
  3. 数据库检查确认订单状态变为"待发货"

五、防御建议

  1. 垂直权限

    • 使用Spring Security或Shiro框架
    • 采用RBAC模型管理角色和权限
    • 最小权限原则分配权限
  2. 水平权限

    • 所有涉及资源ID的操作必须校验归属
    • 使用统一拦截器或AOP处理资源权限
    • 数据库查询自动添加用户ID条件
    • 考虑行级安全(RLS)方案
  3. 代码审计重点

    • 检查所有接收资源ID的接口
    • 验证Service层是否进行归属判断
    • 确保数据库查询包含用户条件
    • 特别注意状态修改类操作
  4. 测试建议

    • 使用不同权限账户测试相同接口
    • 尝试操作非自己拥有的资源ID
    • 自动化扫描工具结合人工验证

六、总结

  1. 垂直权限通常框架完善,风险较低
  2. 水平权限分散在业务代码中,是审计重点
  3. IDOR漏洞难以通过自动化工具发现,需要人工仔细审查
  4. 所有接收资源ID的操作必须进行归属校验
  5. 状态修改类接口需要特别关注权限控制

通过本案例可以看出,即使是在star数很高的开源项目中,水平权限控制也容易出现问题。开发者和安全审计人员都应给予足够重视。

Spring权限管理与IDOR漏洞挖掘实战指南 一、Spring权限管理概述 在企业级应用中,权限控制是核心安全环节。Spring生态提供了丰富的权限管理手段,主要分为两类: 垂直权限(Vertical Access Control) :控制"角色等级"对资源或操作的访问 水平权限(Horizontal Access Control) :防止用户操作自己无权访问的同级资源 二、垂直权限实现方式 1. HandlerInterceptor拦截器 在Spring MVC中,可以通过 HandlerInterceptor 的 preHandle() 方法在请求到达Controller前进行权限校验: 优点 :逻辑集中,可统一管理 缺点 :复杂规则需要手写,维护成本高 2. Spring Security方案 URL级权限 :通过配置URL与角色映射控制访问 方法级注解 : @PreAuthorize :方法执行前校验 @PostAuthorize :方法执行后校验(可基于返回值判断) 自定义PermissionEvaluator :实现复杂业务规则 3. Apache Shiro方案 支持细粒度权限控制,如"document:read:123"表示对ID为123的文档有读权限 4. 自定义注解+AOP 三、水平权限实现方式 水平权限检查依赖资源归属,通常需要分散在业务逻辑或数据库查询层。 1. 数据库层过滤 2. 方法层判断 3. AOP+注解封装 4. 数据库行级安全(RLS) PostgreSQL等数据库支持行级安全策略: 四、IDOR漏洞挖掘实战 以mall项目为例,分析其权限管理实现和漏洞挖掘过程。 1. 垂直权限分析 mall的Security模块中, DynamicSecurityFilter 继承了 AbstractSecurityInterceptor : 核心权限决策流程: AccessDecisionManager.decide() 方法调用 通过 DynamicSecurityMetadataSource.getAttributes() 获取权限规则 规则通过 dynamicSecurityService.loadDataSource() 加载 最终从数据库 ums_resource 表读取URL-角色映射规则 结论 :垂直权限控制完善,难以构造越权。 2. 水平权限漏洞挖掘 漏洞一:订单取消越权 接口 : /order/cancelUserOrder 问题代码 : 利用步骤 : 注册新用户(无任何订单) 从数据库选择其他用户的订单ID(如状态为未支付的73号订单) 向接口发送取消请求: 数据库检查确认订单状态被修改 漏洞二:支付状态篡改 接口 : /order/paySuccess 问题代码 : 严重性 : 实现0元购:未支付订单直接改为已支付 平台攻击:枚举修改大量订单状态,导致交易系统瘫痪 利用步骤 : 选择未支付订单(如73号) 发送支付成功请求: 数据库检查确认订单状态变为"待发货" 五、防御建议 垂直权限 : 使用Spring Security或Shiro框架 采用RBAC模型管理角色和权限 最小权限原则分配权限 水平权限 : 所有涉及资源ID的操作必须校验归属 使用统一拦截器或AOP处理资源权限 数据库查询自动添加用户ID条件 考虑行级安全(RLS)方案 代码审计重点 : 检查所有接收资源ID的接口 验证Service层是否进行归属判断 确保数据库查询包含用户条件 特别注意状态修改类操作 测试建议 : 使用不同权限账户测试相同接口 尝试操作非自己拥有的资源ID 自动化扫描工具结合人工验证 六、总结 垂直权限通常框架完善,风险较低 水平权限分散在业务代码中,是审计重点 IDOR漏洞难以通过自动化工具发现,需要人工仔细审查 所有接收资源ID的操作必须进行归属校验 状态修改类接口需要特别关注权限控制 通过本案例可以看出,即使是在star数很高的开源项目中,水平权限控制也容易出现问题。开发者和安全审计人员都应给予足够重视。