全面防御越权漏洞实战指南

Crushftp 认证绕过漏洞(CVE-2025-2825)

Apache Pinot 认证绕过漏洞(CVE-2024-56325)

 
     越权漏洞的防御需要从服务器端权限校验、角色访问控制、参数验证、会话管理等多维度入手,确保用户只能访问其被授权的资源和功能。

一、水平越权防御:用户数据隔离校验

核心思想:确保用户只能操作自己的数据,禁止跨用户访问。  

 1. 强制绑定用户ID与请求参数

在处理用户数据的接口中,必须校验请求中的用户ID/资源ID是否属于当前登录用户。  

代码示例(Flask + SQLAlchemy):

from flask import Flask, request, jsonify

from flask_login import current_user  # 假设使用Flask-Login管理用户会话



app = Flask(__name__)



@app.route('/api/user/<int:user_id>/info', methods=['GET'])

def get_user_info(user_id):

    # 校验当前用户是否为管理员或请求的user_id属于自己

    if not current_user.is_admin and user_id != current_user.id:

        return jsonify({"error": "无权访问"}), 403

   

    # 查询数据库(假设User模型有id、name等字段)

    user = User.query.get(user_id)

    if not user:

        return jsonify({"error": "用户不存在"}), 404

    return jsonify({"name": user.name, "email": user.email}), 200

2. 使用用户上下文自动过滤数据

在数据库查询层,自动将当前用户ID作为条件,避免手动拼接参数导致的遗漏。  

代码示例(Django ORM):

@RestController

@RequestMapping("/admin")

@SecurityRequirement(name = "role-based-access")

public class AdminController {



    // 仅管理员可访问

    @GetMapping("/users")

    @PreAuthorize("hasRole('ADMIN')")

    public List<User> getAllUsers() {

        return userService.getAll();

}



    // 超级管理员可删除用户

    @DeleteMapping("/users/{id}")

    @PreAuthorize("hasRole('SUPER_ADMIN')")

    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {

        userService.delete(id);

        return ResponseEntity.noContent().build();

    }

}

 二、垂直越权防御:角色权限严格控制

核心思想:基于角色的访问控制(RBAC),确保低权限用户无法访问高权限功能。  

 1. 角色分层与权限注解

定义明确的角色(如`user`、`admin`、`super_admin`),并为每个接口设置访问权限。  

代码示例(Spring Boot + Spring Security):

@RestController

@RequestMapping("/admin")

@SecurityRequirement(name = "role-based-access")

public class AdminController {



    // 仅管理员可访问

    @GetMapping("/users")

    @PreAuthorize("hasRole('ADMIN')")

    public List<User> getAllUsers() {

        return userService.getAll();

}



    // 超级管理员可删除用户

    @DeleteMapping("/users/{id}")

    @PreAuthorize("hasRole('SUPER_ADMIN')")

    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {

        userService.delete(id);

        return ResponseEntity.noContent().build();

    }

}

 2. 自定义权限校验中间件

在请求进入控制器前,通过中间件校验用户角色。  

代码示例(Express.js + JWT):

const jwt = require('jsonwebtoken');

const { SECRET_KEY } = require('./config');



function requireRole(role) {

    return (req, res, next) => {

        const token = req.headers.authorization?.split(' ')[1];

        if (!token) return res.status(401).send('未提供令牌');



        try {

            const decoded = jwt.verify(token, SECRET_KEY);

            if (decoded.role !== role) {

                return res.status(403).send('权限不足');

            }

            req.user = decoded; // 将用户信息挂载到请求对象

            next();

        } catch (error) {

            res.status(403).send('无效的令牌');

        }

    };

}



// 使用示例:仅管理员可访问

app.get('/admin/dashboard', requireRole('admin'), (req, res) => {

    res.send('管理员面板');

});

 三、参数校验与防篡改

核心思想:对用户输入的参数进行严格校验,防止非法参数绕过权限控制。  

 1. 禁止前端控制关键参数

关键参数(如`user_id`、`role`)必须由服务器端生成,禁止前端传递或修改。  

反例(危险做法):

<!-- 前端传递role参数,可被篡改 -->

<form action="/api/update-role" method="post">

    <input type="hidden" name="user_id" value="123">

    <input type="hidden" name="role" value="user"> <!-- 可被修改为admin -->

</form>

正确做法:  

前端仅传递必要的业务参数(如用户输入的内容),权限相关参数由服务器根据登录用户自动填充。  

例如,修改用户资料时,前端无需传递`user_id`,服务器默认使用当前用户ID。

 2. 参数格式与范围校验

对用户ID、资源ID等参数进行格式校验(如整数、UUID)和范围限制(如非负数)。  

代码示例(Python + Pydantic):

from pydantic import BaseModel, PositiveInt

from fastapi import FastAPI, HTTPException



app = FastAPI()



class UserRequest(BaseModel):

user_id: PositiveInt  # 强制校验为正整数



@app.get("/api/user/{user_id}")

def get_user(user_id: int):

    # 使用Pydantic校验参数

    try:

        validated_data = UserRequest(user_id=user_id)

    except ValueError:

        raise HTTPException(status_code=400, detail="无效的user_id")

   

    # 后续校验当前用户是否有权限访问validated_data.user_id

     后续校验当前用户是否有权限访问validated_data.user_id

 四、会话与令牌安全

核心思想:确保用户身份标识不可伪造,防止会话劫持导致越权。  

 1. JWT令牌的正确使用

使用HTTPS传输令牌,防止中间人攻击。  

令牌中仅存储必要的用户信息(如用户ID、角色),敏感信息(如密码)绝不存入。  

采用强签名算法(如HS256、RS256),避免令牌被篡改。  

代码示例(生成与校验JWT,Node.js):

const jwt = require('jsonwebtoken');



// 生成令牌(登录时)

function generateToken(userId, role) {

    return jwt.sign({ userId, role }, SECRET_KEY, { expiresIn: '1h' });

}



// 校验令牌(请求拦截时)

function verifyToken(token) {

    try {

        return jwt.verify(token, SECRET_KEY); // 验证签名并返回 payload

    } catch (error) {

        throw new Error('无效的令牌');

    }

}

 2. Cookie安全属性设置

设置`HttpOnly`、`Secure`、`SameSite`属性,防止XSS窃取Cookie和跨站请求伪造(CSRF)。  

代码示例(Express.js设置Cookie):

res.cookie('sessionToken', token, {

    httpOnly: true,       // 禁止JavaScript访问Cookie

    secure: true,         // 仅通过HTTPS传输

    sameSite: 'strict',   // 防止跨站请求携带Cookie

    maxAge: 86400000      // 有效期1天

});

 五、权限动态校验与最小权限原则

核心思想:权限控制应细粒度到操作级别,而非仅角色级别。  

 1. 基于资源的访问控制(ABAC)

对每个资源(如文件、订单)设置访问策略,结合用户属性(如部门、职位)动态校验权限。  

代码示例(伪代码,模拟文件访问权限):

def can_access_file(user, file_id):

    # 规则:用户属于文件所有者或所在部门的管理员

    file = get_file(file_id)

    return user.id == file.owner_id or user.department == file.department and user.is_department_admin

 2. 最小权限分配

普通用户仅授予基本操作权限(如查询自己的数据),禁止删除、修改等高危操作。  

管理员权限细分:  

  普通管理员:仅能管理指定模块(如用户管理)。  

  超级管理员:拥有全局权限。  

代码示例(权限列表校验,Django):

def has_permission(user, required_permission):

    return required_permission in user.permissions.all()  # 假设用户权限存储为列表



# 使用示例:删除用户需要delete_user权限

@login_required

def delete_user(request, user_id):

    if not has_permission(request.user, 'delete_user'):

        return HttpResponseForbidden("无删除权限")

    # 执行删除逻辑

 六、日志审计与异常监控

核心思想:记录权限相关操作,及时发现异常越权尝试。  

 1. 关键操作日志记录

记录用户ID、操作时间、请求参数、响应状态等信息。  

代码示例(Python logging模块):

import logging



logger = logging.getLogger('access_log')



@app.route('/api/user/<int:user_id>', methods=['GET'])

def get_user(user_id):

    logger.info(f"用户{current_user.id}尝试访问用户{user_id}")

    # 权限校验逻辑...

 2. 异常行为告警

通过监控工具(如ELK、Prometheus)设置规则:  

当同一用户短时间内访问大量不同用户ID时触发告警。  

低权限用户频繁请求高权限接口时触发告警。

 七、避免常见误区

1. 依赖前端控制权限:  

   前端代码可被任意修改,权限校验必须完全在服务器端实现。  

   反例:通过JavaScript隐藏管理员按钮,但用户仍可直接请求管理员接口。

2. 硬编码权限参数:  

   禁止在URL或请求体中直接传递`role=admin`等参数,应通过会话或令牌隐式校验。  

   反例:  

POST /api/delete-user HTTP/1.1  

role: admin  // 可被篡改

3. 忽略未认证用户的越权:  

   未登录用户可能通过公开接口尝试越权(如未授权访问公开数据中的敏感字段),需对匿名请求同样进行参数校验。

 总结:防御越权的核心原则

1. 服务器端严格校验:所有权限逻辑必须在后端实现,禁止依赖前端或客户端。  

2. 数据与权限绑定:用户操作的资源ID必须与当前用户强绑定(如`user_id=当前用户ID`)。  

3. 最小权限与分层:角色权限细分,避免权限滥用;高风险操作(如删除、提权)需二次校验。  

4. 动态校验而非静态判断:根据请求上下文(如资源所有者、操作时间)动态校验权限,而非仅依赖角色。  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值