过度数据暴露:API安全的隐形威胁
在讨论API安全与Web应用安全的差异时,一个突出的观点是:API通常存在数百个小问题,这些问题会随时间累积,而非单一的重大漏洞。
SQL注入固然严重,但那些"按设计"就泄露敏感数据的API呢?这并非比SQL注入更糟,但可能更加隐蔽,因为它会放大你拥有的每一个其他漏洞。
过度数据暴露:沉默的问题
这种模式随处可见。比如一个端点 GET /api/users/123 返回:
|
|
但同时也会返回:
|
|
以及许多你本不打算暴露的数据。前端只显示姓名和邮箱,但API却返回了数据库中的所有内容。
你可能会想:“但只有认证用户才能调用此端点,所以没问题!“确实如此。但当攻击者入侵任何用户账户时会发生什么?当开发者意外记录完整响应时?当浏览器扩展抓取数据时?当响应被缓存到不该缓存的地方时?所有这些敏感数据就那样暴露在外,等待被利用。
最糟糕的是?这会与其他漏洞叠加。假设你有一个BOLA漏洞,用户可以通过更改ID访问其他用户的数据。如果你的API只返回公共字段,影响将是有限的。但如果它泄露PII、内部ID或敏感业务数据,那么这个BOLA漏洞就可能演变成大规模数据泄露。
为何这个问题无处不在
这不是恶意的,通常是为了方便。返回整个对象比过滤字段更快。ORM也没有帮助,除非显式使用投影或选择特定字段,否则它们默认返回所有内容。有时团队试图聪明地"面向未来"设计API,包含可能需要的字段。有时?只是复制粘贴。一个端点这样做了,其他端点就跟着做。
从开发速度的角度看,这是有道理的。在压力下发布功能时,我自己也这样做过。你编写一个快速端点,测试前端显示正确,然后发布。API返回20个字段但UI只使用3个?没人注意到,因为它能工作。
实际影响
举一个代码审查中的具体例子。一个在线学习平台有一个端点 GET /api/courses/{courseId}/students,返回学生注册数据。教师查看学生信息是合理的,对吧?但它不只是返回姓名和进度百分比,还返回完整的邮箱地址、注册日期、支付状态、测验尝试历史记录(含时间戳)、讨论论坛活动指标,甚至学生访问课程的设备信息。
前端只显示学生姓名和课程完成百分比。如果你是学生?在UI中只能看到自己的状态。但任何注册学生都可以直接调用该端点,更改课程ID,并获取其他课程的数据。有人可以遍历课程ID,构建完整的数据库,了解谁在修什么课程、支付模式、学习行为和个人联系信息。他们不需要破坏任何东西或寻找巧妙的漏洞利用方法,API就直接交出了所有数据。
幸运的是,这在进入生产环境前被发现了,但由于功能在UI和API中都能正常工作,这很容易溜进生产环境。
再谈谈PII的影响。那些泄露的学生数据?包括全名、邮箱地址、电话号码、实际地址,可能还有支付信息。在许多司法管辖区,这是等待发生的GDPR违规或等效问题。即使攻击者从未恶意使用这些数据,你也已经面临监管罚款、强制违规通知和公关噩梦。仅仅因为API返回了15个没人真正需要的额外字段。商业情报泄露对竞争不利,但PII暴露?这会让你因为错误的原因登上技术频道的头条。
另一个常见模式:分页端点泄露过多信息。调用 GET /api/students?page=1&limit=100 期望得到学生列表,但返回的不仅是学生信息,还有他们的哈希密码、API密钥、内部权限、最后登录时间、IP地址……所有这些都不应该离开后端。
规模问题
SQL注入是一个漏洞,找到并修复它就完成了。过度数据暴露?那是数百个端点,每个都泄露一点数据,随时间累积。
攻击者更容易利用哪一个?存在于每个端点中的那个。他们不需要找到巧妙的注入载荷,只需要遍历你的API并收集你免费提供的一切。而且因为"技术上按设计工作”,它甚至可能不会触发你的安全监控。没有失败的请求,没有可疑的载荷,只是正常的API调用返回了过多信息。
其他"无聊"但重要的漏洞
还有批量分配——用户发送 {"name": "Deckan", "isAdmin": true},API就……接受两个字段。没有验证什么应该可更新。突然之间,普通用户变成了管理员。
或者不恰当的速率限制。密码重置无限制?通过暴力破解接管账户。OTP验证无限制?再见,2FA。搜索无限制?恭喜,有人刚刚抓取了你整个数据库。
还有经典问题:可预测的资源ID。/api/invoices/1001,/api/invoices/1002……你明白这意味着什么。攻击者只需遍历并收集一切。经典的BOLA。
为何难以解决
这些不是那些登上头条的性感零日漏洞,而是嵌入数十或数百个端点的架构问题。找到它们意味着真正理解每个端点的作用。你需要知道每个端点返回什么、需要返回什么,以及哪些只是额外负担。然后乘以API中的每个端点。这很乏味,但很重要。
这就是API安全测试棘手的原因。你不是在寻找一个大漏洞,而是在检查每个端点的这些模式。数据在不该泄露的地方泄露、缺失的身份验证检查、不存在的速率限制。所有这些问题无处不在,并且相互叠加。在Detectify,我们的API扫描处理了繁琐的部分,系统地检查每个端点的漏洞。这样你的团队可以花时间在真正需要人类判断的事情上,比如业务逻辑漏洞和理解你特定应用的安全上下文。
你的团队如何处理这个问题?
我们想了解:在构建新端点时,你如何确保开发者只返回必要的字段?代码审查?自动检查?强制显式字段选择的响应DTO?