如何修复Hibernate delete方法触发的CWE-566用户可控SQL主键授权绕过问题
漏洞修复方案
Veracode报告的漏洞核心是缺少操作权限校验,而非单纯的实体存在性校验。该漏洞属于典型的越权操作风险:如果待删除实体的主键由前端传入且未做权限校验,攻击者可以通过篡改主键值删除任意用户的记录。
修复步骤
第一步:禁止直接使用前端传入的游离实体执行删除
前端传入的实体的主键可能被恶意篡改,删除前必须先根据主键从数据库查询到持久化状态的实体,同时也完成了实体存在性校验。第二步:增加操作权限校验
拿到持久化实体后,必须校验当前登录用户是否具备该实体的删除权限,比如:- 普通用户只能删除自己的账号
- 管理员只能删除自己管辖分组下的用户
- 超级管理员可以删除所有用户
第三步:代码实现示例
业务层调用删除前的校验逻辑参考:
如果要在泛型DAO层统一封装校验逻辑,可以改造delete方法:public void deleteTargetUser(Long targetUserId) { // 从数据库查询待删除实体 User targetUser = getHibernateTemplate().get(User.class, targetUserId); if (Objects.isNull(targetUser)) { throw new RuntimeException("待删除用户不存在"); } // 获取当前登录用户 User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); // 权限校验:仅管理员或用户本人可删除 boolean hasPermission = currentUser.isAdmin() || targetUser.getId().equals(currentUser.getId()); if (!hasPermission) { throw new AccessDeniedException("无权限删除该用户"); } // 校验通过后执行删除 connectionDAO.delete(targetUser, nbMaxConnections); }
调用时传入对应业务的校验规则即可:public void delete(T entity, final boolean cachable, Predicate<T> permissionValidator) { // 先查询持久化实体,假设所有实体继承了带getId方法的BaseEntity基类 T persistentEntity = (T) getHibernateTemplate().get(entity.getClass(), ((BaseEntity) entity).getId()); if (Objects.isNull(persistentEntity)) { throw new IllegalArgumentException("待删除实体不存在"); } // 执行权限校验 if (!permissionValidator.test(persistentEntity)) { throw new AccessDeniedException("无操作权限"); } getHibernateTemplate().setCacheQueries(cachable); getHibernateTemplate().delete(persistentEntity); }connectionDAO.delete(user, nbMaxConnections, targetUser -> currentUser.isAdmin() || targetUser.getId().equals(currentUser.getId()) );
常见误区说明
单纯校验实体是否存在无法解决该漏洞,因为攻击者可以传入任意存在的其他用户的主键,只要没做权限校验,仍然会产生越权删除的风险。
内容的提问来源于stack exchange,提问作者M. Yousfi
相关产品推荐
相关产品推荐

