第17天 — 我构建了一个易受攻击的 API 来演示批量赋值攻击
Source: Dev.to
(请提供您希望翻译的正文内容,我将为您翻译成简体中文。)
介绍
有些漏洞并不需要复杂的利用方式。
有时只需要后端对用户输入的信任稍微多一点。今天,我构建了一个小型 Flask API 来演示一种微妙但危险的问题——批量赋值(Mass Assignment)。
现代框架通过自动将用户输入映射到数据库对象,使开发变得快速。例如,在更新用户资料时,开发者常常接受 JSON 数据并直接应用到用户记录上:
user.update(request.json)方便,但也很危险。如果应用程序盲目接受客户端发送的每一个字段,攻击者就可以修改那些本不应由用户控制的隐藏或敏感字段。这就是批量赋值漏洞出现的地方。
演示设置
Flask API 包括:
- 用户登录
- 查看个人资料
- 个人资料更新端点
- 管理员面板
SQLite 数据库存储用户信息,其中包括一个内部字段 is_admin,普通用户不应能够修改。在易受攻击的版本中,更新端点完全信任客户端。
易受攻击的更新逻辑
fields = ["username", "email", "password", "is_admin"]
for field in fields:
if field in data:
cur.execute(
f"UPDATE users SET {field}=? WHERE id=?",
(data[field], session["user_id"])
)因为服务器接受请求体中出现的任何字段,恶意负载例如:
{
"email": "new@email.com",
"is_admin": 1
}将会在没有任何额外检查的情况下更新管理员标志。
漏洞利用步骤
以普通用户登录
POST /login Content-Type: application/json { "username": "testuser", "password": "password123" }API 会返回一个会话 Cookie。
发送构造的个人资料更新请求
POST /update_profile Content-Type: application/json Cookie: { "email": "new@email.com", "is_admin": 1 }服务器在未进行验证的情况下处理该请求,并将
is_admin设置为1。访问管理员面板
GET /admin Cookie:响应:
Welcome Admin. System secrets unlocked.
特权提升在从登录到获取管理员访问权限的 30 秒内完成。
为什么会出现批量赋值
批量赋值漏洞发生在以下情况:
- 框架自动将用户输入绑定到对象。
- 模型中存在敏感字段。
- 开发者未限制可以被更新的字段。
常见场景包括:
- REST APIs
- ORM(例如 SQLAlchemy、ActiveRecord)
- 自动绑定框架(例如 Spring)
- JSON 请求处理
真实案例的影响范围从未授权的角色更改到电商平台的折扣超额领取。OWASP 将其列在 A03:2021 – Injection(更广泛的类别)下,但它看起来“只是一次更新”,因此容易被忽视。
缓解措施:字段白名单
不要接受所有参数,而是显式定义用户可以修改的字段。
allowed_fields = ["username", "email", "password"]
for field in allowed_fields:
if field in data:
cur.execute(
f"UPDATE users SET {field}=? WHERE id=?",
(data[field], session["user_id"])
)现在,即使攻击者在请求中包含 is_admin,也会被忽略。
对于 ORM,使用模型层面的保护,例如:
@JsonIgnore(Jackson,Java)attr_readonly(SQLAlchemy,Python)
这些注解可强制敏感属性不可变。
结论
该实验表明,安全漏洞常常隐藏在便利性中。单个未验证的参数就能将普通用户提升为管理员。在构建 API 时,需审计更新端点是否正确进行白名单过滤。像 OWASP ZAP 或简单的 Burp Suite 代理等工具可以快速发现这些问题。记住:用户输入绝不应决定内部系统字段的行为;后端必须始终决定哪些可以、哪些不能被修改。