在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_id 或 current_user.id |
安全漏洞 |
✅ 总结:如何防止 JWT 横向越权?
| 步骤 | 措施 |
|---|---|
| 1️⃣ | JWT 只负责身份认证,不能自动控制访问范围 |
| 2️⃣ | 每个接口必须校验"当前用户是否拥有该资源" |
| 3️⃣ | 使用数据库中的 owner_id 字段进行归属校验 |
| 4️⃣ | 避免依赖可猜的 id,建议使用 UUID 或短 ID |
| 5️⃣ | 结合角色权限系统(RBAC)实现更细粒度控制 |
🎯 Tips:
"JWT 是身份证,但不能当门禁卡。真正的访问控制,必须在后端做校验。"