API 安全攻防:认证、授权与 OWASP API Top 10
为什么 API 安全如此重要
现代应用几乎都建立在 API 之上。无论是移动应用、单页应用还是微服务架构,API 都是数据交换与业务逻辑的核心通道。正因其广泛暴露和直接访问后端数据的特性,API 已成为攻击者的首选目标。传统 Web 安全关注表单、会话,而 API 安全需要全新的视角:无状态认证、细粒度授权、数据暴露控制以及速率限制等。OWASP API 安全项目提供了系统化的威胁模型与防御指南,是每一位开发者与安全工程师必须掌握的知识。
OWASP API 安全 Top 10 概览
OWASP API Security Top 10 专为 API 场景设计,聚焦最关键的十大风险。最新版本(2023)仍保持动态更新,核心风险类别与 2019 版一脉相承,但更强调授权缺陷与数据暴露。下表将 10 大风险按类型分组,以帮助快速建立认知地图。
| 风险编号 | 名称 | 核心问题 |
|---|---|---|
| API1 | 失效的对象级授权 (BOLA) | 针对同一对象的请求未做用户权限校验 |
| API2 | 失效的用户认证 | 认证机制本身存在漏洞,可被绕过 |
| API3 | 过度的数据暴露 | API 响应返回过多字段,依赖客户端过滤 |
| API4 | 缺乏资源与速率限制 | 可被暴力攻击、爬取或拒绝服务 |
| API5 | 失效的功能级授权 (BFLA) | 不同功能端点未实施适当角色校验 |
| API6 | 批量分配 | 用户传入参数被绑定到内部对象属性,导致越权修改 |
| API7 | 安全配置错误 | 错误信息泄露、不安全的 HTTP 头、默认配置 |
| API8 | 注入 | SQL、NoSQL、命令注入等 |
| API9 | 资产管理不当 | 已废弃、调试或旧版 API 未关闭 |
| API10 | 日志记录与监控不足 | 无法及时发现攻击或数据泄露 |
以上风险中,对象级授权与功能级授权是 API 安全的两大基石,几乎所有破坏性攻击都源于此。接下来我们将深入实战,剖析这些风险并给出可落地的防御方案。
认证 —— 谁在敲门?
不要自己造轮子
永远不要自行设计认证协议。使用经过广泛审计的标准方案:OAuth 2.0 + OpenID Connect 用于用户委托授权与身份验证;对于服务间通信,优先选择 Mutual TLS 或预共享密钥的 Bearer 令牌。避免 Basic Auth 在没有 TLS 的情况下使用,因为凭据几乎以明文传输。
令牌管理实践
- JWT 的使用:签名很重要,务必使用非对称算法(RS256/ES256)或强对称密钥(HS256),并在服务端验证签名。敏感载荷必须加密(JWE)。
- 短期令牌与刷新令牌:访问令牌(access token)过期时间应短,例如 15 分钟。客户端使用刷新令牌(refresh token)换取新访问令牌,刷新令牌应绑定客户端并支持轮转。
- 撤销机制:维护令牌黑名单或使用短过期时间 + 无状态签名。注意不要在 JWT 中存储过多敏感数据,因为它们默认只是 Base64 编码,不是加密。
API 密钥与微服务
对于机器对机器调用,API 密钥容易泄露且难以轮换。推荐使用 OAuth 2.0 客户端凭证流,并为每个客户端生成独立凭据,同时施加最小权限。密钥必须通过环境变量或密钥管理服务注入,严禁硬编码。
授权 —— 你能做什么?
对象级授权 (BOLA)
这是 API 安全中最普遍且危害最大的漏洞。当 /api/users/{id} 接口只校验用户是否登录,而未校验登录用户的 ID 是否与 {id} 匹配时,攻击者通过遍历 ID 即可访问所有用户数据。
防御策略:
- 所有权校验:始终从认证会话中提取当前用户 ID,并将其与请求的资源所有者 ID 比较。避免仅依赖客户端传入的 ID。
- 使用不可预测的标识符:对于公开资源,使用随机 UUID 而不是自增数字,但决不能仅靠混淆来保证安全。
- 集中授权层:不要在业务逻辑中散落授权判断,而是用中间件或 AOP 统一校验,确保每个端点都经过授权检查。
功能级授权 (BFLA)
BOLA 检查“你能访问这个对象吗”,而 BFLA 检查“你能调用这个操作吗”。例如普通用户能否访问 /admin/export 端点。
防御策略:
- 基于角色的访问控制:在路由层定义所需角色,如
@RolesAllowed("ADMIN")。 - 默认拒绝:除非显式允许,否则拒绝所有请求。
- 测试覆盖:编写自动化测试,用不同角色账户尝试访问每个端点,确保权限边界无遗漏。
批量分配与属性越权
批量分配通常发生在对象映射框架中,当接收 JSON 请求体时,直接绑定到内部数据模型。攻击者可能发送 {"role":"admin"} 把自己的账号提权。
防御:
- 定义允许字段白名单,永远不要直接将用户输入绑定到持久化对象。使用 DTO 并显式列出可设置的属性。
- 区分用户可更新属性和内部属性。例如“注册时间”、“余额”等必须只能由服务端修改。
如何应对数据泄露与信息过载
最小化数据返回
API 响应应该只包含客户端真正需要的字段,而不是返回整个数据库行。常见错误是 GET /user 返回密码哈希、安全答案、内部标签等。
实践:
- 序列化与视图模型:针对不同角色、不同场景(列表 vs 详情)定义不同响应结构。
- GraphQL 同样需要控制:即使客户端可以决定字段,也要在解析器中校验字段级权限。
- 分页与过滤:避免一次返回大量记录,强制分页参数并提供合理的默认上限。
安全头与错误信息
- 屏蔽技术栈:移除
X-Powered-By等头,错误响应仅返回通用消息。 - 避免泄漏堆栈跟踪:生产环境关闭调试模式,返回
{"error":"invalid_request"}而非详细的代码行号。 - CORS 配置:不要使用
Access-Control-Allow-Origin: *,尤其是在 API 使用凭证(cookies)时。应精确指定允许的源。
速率限制与资源保护
缺少速率限制,攻击者可通过暴力破解令牌字典、爬取数据或耗尽计算资源来影响服务。API 应当:
- 为敏感端点(登录、注册、密码重置)设置严格的速率限制,如 5 次/分钟。
- 使用滑动窗口或令牌桶算法,避免可预测的固定窗口复位。
- 基于 IP、用户 ID 或 API 密钥多维度限流。
- 对超出限制的请求返回
429 Too Many Requests,并在响应头中告知限制状态。
注入攻击:不仅是 SQL
API 同样需要防范注入,包括 SQL、NoSQL、命令注入以及表达式语言注入。当查询参数或请求体直接拼接到查询语句中时就会产生风险。
防御:
- 参数化查询:永远不要拼接字符串构建查询, ORM 也应使用安全的查询构建方式。
- 输入验证与净化:根据数据类型进行严格白名单校验(例如整数、邮箱格式)。
- 小心 NoSQL 操作符注入:比如 MongoDB 的
$gt、$ne可能被用在 JSON 输入中,确保输入是纯净的值而非操作符。
资产管理:你忘了那个旧接口
过时或影子 API 是攻击者的乐园。开发者经常忘记下线旧版本、测试端点或内部调试功能。
最佳实践:
- API 清单:定期自动发现所有公开接口,使用 swagger/OpenAPI 文件治理。
- 版本控制:清晰设定 API 生命周期,废弃接口在响应头中加入
Deprecation和Sunset头。 - 仅暴露必要端点:生产环境移除
/swagger-ui、/api-docs等文档,或使用强认证保护。
日志与监控:最后一道防线
没有足够的日志,你永远无法知道什么时候发生了入侵。日志需要记录谁、在什么时间、做了什么操作、结果如何。
- 记录所有认证尝试(成功与失败)。
- 记录敏感操作,如权限变更、大量数据导出。
- 避免记录敏感数据:令牌、密码、个人身份信息不应写入明文日志。
- 集成 SIEM 或警报系统,对异常模式(如突然的大量 403 错误)及时响应。
总结:纵深防御体系
OWASP API 安全最佳实践并非单个技术点,而是一套纵深防御体系。认证确保身份可信,授权保证最小权限,数据的谨慎输出减少泄露面,限流和日志提供韧性。将 OWASP API Top 10 内化为团队的威胁模型,并融入软件开发生命周期,从设计、编码到测试、监控,每一个环节都应嵌入这些校验点。
建议从今天起,在你的 API 代码库中检查以下三个最容易被忽视的地方:
- 每个端点是否都对当前用户进行了对象所有权检查?
- 响应 JSON 是否可能泄露了不必要的字段?
- 是否有未进行速率限制的认证相关端点?
修复这些问题,就已经堵住了绝大多数 API 攻击的入口。