JWT机制下防越权:后端校验是关键

在JWT 机制下,如何保证用户请求接口时不会横向越权(即 A 用户能访问 B 用户的数据)?


✅ 核心答案:

JWT 本身不解决越权问题,它只负责"身份认证"
防止横向越权,必须在后端接口中加入"资源归属校验"逻辑。


🔍 一、什么是横向越权?

越权类型 说明 示例
横向越权 用户 A 可以访问用户 B 的数据 GET /api/users/123 返回张三信息,但张三没权限看李四数据
纵向越权 低权限用户访问高权限接口 普通用户调用 DELETE /api/admin/users/1

JWT 的 token 只能证明"你是谁",不能自动限制"你能看什么"


✅ 二、如何防止横向越权?(关键防御措施)

✅ 1. 后端接口必须校验"当前用户是否拥有该资源"

✅ 示例:获取用户信息接口
python 复制代码
# backend/main.py
@app.get("/users/{user_id}")
async def get_user(user_id: int, current_user: User = Depends(get_current_user)):
    # 关键:校验 user_id 是否等于当前登录用户的 id
    if current_user.username != "admin" and user_id != current_user.id:
        raise HTTPException(status_code=403, detail="Forbidden: You can only access your own data")

    # 模拟数据库查询
    return {"id": user_id, "username": "testuser", "email": "test@example.com"}

💡 这里 current_user 是从 JWT 解码得来的,但你必须 显式判断 current_user.id == user_id


✅ 2. 使用数据库中的"owner_id"字段做归属校验

在数据库中,每个资源都应该有 owner_id 字段。

✅ 示例:用户文章表(posts
sql 复制代码
CREATE TABLE posts (
    id INT PRIMARY KEY,
    title VARCHAR(255),
    content TEXT,
    owner_id INT REFERENCES users(id),  -- 关键:谁拥有这篇 post
    created_at DATETIME
);
✅ 后端查询文章时:
python 复制代码
@app.get("/posts/{post_id}")
async def get_post(post_id: int, current_user: User = Depends(get_current_user)):
    # 1. 查询数据库中的 post
    post = db.query(Post).filter(Post.id == post_id).first()
    if not post:
        raise HTTPException(status_code=404, detail="Post not found")

    # 2. 核心校验:当前用户是否是该 post 的 owner
    if post.owner_id != current_user.id:
        raise HTTPException(status_code=403, detail="Forbidden: You can't access this post")

    return post

✅ 这样即使 A 用户知道 B 用户的文章 ID,也无法访问。


✅ 3. 避免使用 id 作为公开参数(可选优化)

如果 API 返回的是 post/123,攻击者可以暴力枚举 1,2,3,...

✅ 建议:
  • 使用 UUID 或短 ID(如 post/abc123
  • 同时在数据库中存储 owner_id,确保访问控制不依赖 ID 可猜性

✅ 4. 结合角色权限系统(RBAC)做更细粒度控制

  • admin 可以查看所有用户数据
  • normal_user 只能查看自己的数据
python 复制代码
if current_user.role == "admin":
    # 允许查看任意用户
else:
    # 只允许查看自己
    if current_user.id != user_id:
        raise HTTPException(status_code=403, detail="Forbidden")

🚫 常见错误做法

错误做法 风险
只靠 JWT 解码用户名就返回数据 横向越权
前端传 user_id 就信任它 容易被篡改
不校验 owner_idcurrent_user.id 安全漏洞

✅ 总结:如何防止 JWT 横向越权?

步骤 措施
1️⃣ JWT 只负责身份认证,不能自动控制访问范围
2️⃣ 每个接口必须校验"当前用户是否拥有该资源"
3️⃣ 使用数据库中的 owner_id 字段进行归属校验
4️⃣ 避免依赖可猜的 id,建议使用 UUID 或短 ID
5️⃣ 结合角色权限系统(RBAC)实现更细粒度控制

🎯 Tips:

"JWT 是身份证,但不能当门禁卡。真正的访问控制,必须在后端做校验。"