全网最详细的Spring入门教程
Web API 安全冠军第 III 部分:损坏对象属性级别授权 (OWASP TOP 10)
损坏的对象属性级别授权
描述
Broken Object Property Level Authorization 是一种 API 漏洞,允许攻击者绕过访问控制机制,并在没有适当权限的情况下操纵对象的单个属性。当 API 未在资产级别充分实施授权检查时,就会出现此漏洞,从而使未经授权的用户能够修改对象中的敏感字段。虽然类似于 Broken Object Level Authorization,但此漏洞侧重于对象中的特定属性,而不是整个对象本身。此漏洞也称为 “Mass Assignment” 漏洞。
在我的职业生涯中,我观察到许多 Broken Object Property Level Authorization 漏洞。当将同一数据模型用于各种 CRUD 操作而未实施精细授权检查时,通常会出现这些问题,前提是资产级访问不需要与对象级操作相同的审查。此漏洞被列为 OWASP TOP 10 API 安全风险之一。
影响
了解对象及其属性的攻击者可能会更新、修改或删除该对象中的信息。根据特定属性及其在应用程序中的角色,这可能会导致数据泄露、未经授权的交易或其他重大安全影响。例如,修改用户的角色属性以提升权限或更改财务应用程序中的交易金额可能会产生严重后果。
下面列出了通过 HackerOne 报告的此漏洞的两个示例:
案例研究 — Damn Vulnerable RESTaurant API
为了说明这种漏洞,我将使用我的开源项目 — Damn Vulnerable RESTaurant API。这个项目可以在我GitHub上找到:Damn Vulnerable RESTaurant API
Damn Vulnerable RESTaurant API 介绍
Damn Vulnerable RESTaurant 是一个故意设计成存在安全漏洞的网络应用程序,供开发者探索和修复安全问题。它是开发者、道德黑客和安全工程师的优秀资源。
漏洞描述
破碎的对象属性级别授权漏洞存在于 PUT API 端点中。这个端点处理个人资料更新操作。用户可以更新由模式指定的各种字段。不幸的是,用户包括字段,这些字段也可能被用户更新。结果,一个普通客户用户可以通过更新角色字段来执行权限提升,将其改为Employee
或Chef
。
以下是 FastAPI 中易受攻击的 API 端点实现:
from apis.auth.schemas import User as UserSchema
...
@router.put("/profile", response_model=UserRead, status_code=status.HTTP_200_OK)
def update_current_user_details(
user: UserSchema,
current_user: Annotated[User, Depends(get_current_user)],
db: Session = Depends(get_db),
):
db_user = update_user(db, user.username, user)
return current_user
User class with 字段如下所示:role
class User(BaseModel):
username: str
first_name: Union[str, None] = None
last_name: Union[str, None] = None
phone_number: Union[str, None] = None
role: Union[str, None] = None
损坏的对象属性级别授权概念验证
利用此漏洞非常简单。例如,可以发送以下 curl HTTP 请求来更改当前用户的角色,以对餐厅的员工执行权限提升:
curl -X 'PUT' \
'http://localhost:8080/profile' \
-H 'accept: application/json' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJNaWtlIiwiZXhwIjoxNzE2NzUxNjYwfQ.8khfY1H_2VLZPNuxptkEdOstuJlpME6ZAJNGnKZKFd0' \
-H 'Content-Type: application/json' \
-d '{
"username": "Mike",
"role": "Employee"
}'
下面显示的 HTTP 响应正文成功地将角色更新为 Employee:
{
"username": "Mike",
"first_name": "Mike",
"last_name": "",
"phone_number": "",
"role": "Employee"
}
损坏的对象属性级别授权修复
要修复此漏洞,建议实施一个新架构,该架构定义用户可以更新哪些字段。这样,用户将无法更新架构中未包含的字段。以下代码段显示了不包含 field 的新架构。UserUpdate
UserUpdate
role
class UserUpdate(BaseModel):
username: str
first_name: Union[str, None] = None
last_name: Union[str, None] = None
phone_number: Union[str, None] = None
现在,UserUpdate 模式可以在如下所示的功能中使用:update_current_user_details
rom apis.auth.schemas import UserUpdate
...
@router.put("/profile", response_model=UserRead, status_code=status.HTTP_200_OK)
def update_current_user_details(
user: UserUpdate,
current_user: Annotated[User, Depends(get_current_user)],
db: Session = Depends(get_db),
):
db_user = update_user(db, user.username, user)
return current_user
损坏的对象属性级别授权建议
为了防止此类漏洞,我建议采取以下措施:
- 默认拒绝访问:遵循最小权限原则,仅授予特定角色所需的权限。
- 使用基于架构/DTO 的验证机制,每个 CRUD 操作具有不同的架构,以确保只能访问或修改指定的字段。
- 实施精细授权检查:确保在对象和属性级别都检查授权。
- 根据终端节点的业务/功能要求,将返回的数据结构保持在最低限度。
- 使用不可预测的标识符:通过使用 GUID 或其他非顺序标识符来防止暴力尝试。
- 为资产级访问编写单元测试:确保单元测试涵盖未经授权的访问尝试。
- 执行代码审查:定期审查代码以识别潜在的安全问题。
建议的单元测试,以确保未经授权的用户无法修改用户的角色:
def test_update_role_by_customer_ignores_role_returns_200(test_db, customer_client):
data = {
"username": "customer",
"role": "Employee",
}
response = customer_client.put("/profile", json=data)
assert response.status_code == 200
assert db_customer.role == UserRole.CUSTOMER
破损对象属性级别授权自动检测
手动或通过代码审查检测此类漏洞可能很有效。此外,静态应用程序安全测试和动态应用程序安全测试工具可以帮助自动化检测过程,但它可能需要根据所使用的技术调整自定义规则/工作流程。在撰写本文时,通过自动化工具检测此类漏洞具有挑战性,如果不进行适当的项目特定调整,可能无法提供令人满意的结果。
在本系列的第一篇文章中,我介绍了如何开发自定义 Semgrep rool 来检测特定于项目的易受攻击模式 — Web API Security Champion II: Broken Object Level Authorization。
总结
在本文中,我为开发人员和安全工程师介绍了 Broken Object Property Level Authorization 漏洞,并提供了实际示例、修复和建议。这种对检测和解决此类漏洞的见解将帮助您构建更安全的 API。
如何找到更多同类API?
幂简集成是国内领先的API集成管理平台,专注于为开发者提供全面、高效、易用的API集成解决方案。幂简API平台可以通过以下两种方式找到所需API:通过关键词搜索API、或者从API Hub分类页进入寻找。