大多数团队把 API 安全当成身份验证问题:发放令牌,在每一条路由上校验它,然后认为事情已经做完了。直到某天,一位测试人员把 URL 里的一个数字改掉,就读到了另一位客户的发票。

「已通过身份验证」和「已获得授权」之间的这道缝隙,正是绝大多数真实 API 泄露事件栖身的地方,而且它并不是扫描器能够稳定发现的那类问题。自动化工具看到一个有效的令牌和一个 200 响应,就报告成功。只有理解你业务规则的人,才会注意到那个响应里装的是别人的数据。

核心区别: 身份验证证明的是谁在调用。授权决定的是这个特定调用方可以看到什么、可以修改什么,而且它必须落实到每一个对象、每一次请求,并在数据层强制执行。几乎所有严重的 API 漏洞,都是第一件事运转完美、第二件事失守的结果。


对象级授权失效为什么占了绝大多数

最常见的严重 API 缺陷,也是最容易描述的那一个。

你的端点是 /api/invoices/48213。调用方已经通过身份验证,于是处理器取出发票 48213 并把它返回。没有人检查这张发票是否属于该调用方。换个数字,就拿到别人的发票。API 完全按照写出来的样子运行了,写错的是那段代码本身。

这个缺陷的规模效应对你不利,对攻击者有利。连续递增的标识符让人只用一个循环就能枚举出你的整个数据集。改用难以猜测的标识符略有帮助,但那不是修复,因为标识符仍会通过其他端点、导出文件和邮件泄漏出去。

修复必须是结构性的,而不是顺手补一刀。所有权要在查询本身里校验:取出属于这位客户、且具有这个标识符的发票,而不是先把发票取出来,再指望后面某段代码会做检查。把这项强制放进数据访问层,这样六个月后某个从没读过这段话的人写新控制器时,也不可能把它忘掉。

同样的失效不仅适用于对象,也适用于功能。如果一个管理端点唯一的保护,只是普通用户的后台界面没有链接到它,那么它根本没有受到保护。


真正会被查出来的 API 安全缺陷

除授权之外,还有少数几类问题占了大部分发现。这里的标准参考是 OWASP API Security Top 10,OWASP 会定期修订它,所以请查阅当前版本,而不是某份摘要。

返回的东西比界面展示的更多。 某个端点图省事返回了完整的用户对象,前端只显示其中三个字段。其余十二个,包括密码重置令牌和内部风险评分,仍然留在响应里。任何打开网络面板的人都能拿到它们。序列化要有意为之:用逐个点名的字段拼出响应,而不是把一个模型整个倒出去。

入站方向的批量赋值。 这是上一个问题的镜像。一个资料更新端点来什么字段就收什么、并写进记录,于是调用方加上一句 "role": "admin" 就把自己提成了管理员。请显式绑定到允许字段清单,而不是整份接收请求体。

消耗没有上限。 没有限制的话,一个调用方可以每页请求一百万条记录,在循环里跑昂贵的搜索,或者触发上千次密码重置。这不只是拒绝服务的问题:当每一次请求都在花你的钱,比如端点背后接着一个语言模型时,这就是一场针对账单的攻击。速率限制应当按调用方、按端点分别设置,昂贵的操作要比廉价的操作勒得更紧。

资产清单与对第三方的信任

没有文档、被遗忘的端点。 第二版已经上线并有文档,第一版却还带着旧的授权逻辑在跑,而一套装着生产数据的预发布 API 从公网就能访问。攻击者要找的正是这些。请为每一个已部署的 API、每一个版本、每一套环境维护清单,并且有意识地下线,而不是任其荒废。

信任你所调用的系统。 你的 API 会消费别人的 API,而它们的响应会直接落进你的数据库和渲染结果里。不要因为对方是合作伙伴就假定安全,请校验回来的内容。上游的故障或规格变更,最后往往以你这边的缺陷形式浮现出来。同一段关系里可靠性的一面,我们在第三方 API 集成 的指南里讲过。


把身份验证做对

身份验证是多数团队大体做对了的部分,所以这一节谈的是那些会把它毁掉的细节。

使用带刷新机制的短期访问令牌,而不是永不过期的长期密钥。一份永远有效的凭据一旦泄露,就是一次永久性的入侵;一份十五分钟后失效的凭据泄露了,那是一起有明确终点的事件。

把令牌的作用域收窄。签发给报表集成的令牌,不应该有创建用户的能力。有了作用域,你就能在中心位置强制这一点,而不必依赖每个处理器自己去检查。

正确地校验令牌,这多半意味着不要接受令牌自己声明的算法。固定你预期的签名算法,校验签发者和受众,并检查过期时间。默认就这样做的库是存在的;错误几乎都住在手写的校验逻辑里。

按计划轮换凭据,并给调用方提供一条不停机的轮换路径,通常是在切换期间同时接受两把有效密钥。如果轮换会造成停机,那就没有人会去轮换。

最后,永远不要把凭据放进 URL。查询字符串最终会出现在服务器日志、浏览器历史、代理日志和 referrer 头里。请使用请求头。


渗透测试实际会发现什么

自动扫描和人工测试发现的东西不同,你出于不同的理由需要两者。

扫描器擅长找出已知有漏洞的依赖、缺失的安全响应头、TLS 配置错误和明显的注入。请让它们在流水线里持续运行,因为它们便宜,而且能抓住回退。

它们做不到的,是理解你的业务。测试人员会发现优惠码端点可以反复调用来叠加折扣,会发现付费功能在免费套餐下直接调 API 就能用,会发现发货之后取消订单会在不核对库存的情况下触发退款。这些才是真正让人赔钱的发现,而它们只有在有人真正明白这套 API 是干什么用的时候才会浮出水面。

具体到 API,请要求测试范围包含跨角色的授权测试,也就是测试人员同时持有两个不同客户的凭据,系统性地尝试用其中一方的令牌去访问另一方账户的数据。单这一项练习,找出的问题就比其余全部加起来还多。我们关于渗透测试类型 的文章说明了应该给测试人员多少访问权限,而把文档和凭据交给他们,效果远好过一次盲测。

预算方面,以 API 为核心的测试通常从一个小而文档齐备的 API 约 £3,000 起,到一个角色众多、集成众多的大面积接口 £15,000 甚至更高。我们的渗透测试费用指南 拆解了推动这个区间的因素。


记录足够多,事后才查得清

一起事件和一场灾难之间的差别,通常就在于你能否复原当时到底发生了什么。

请记录身份验证事件、授权失败,以及每一次改变状态的操作,并附上调用方身份、目标对象和一个关联标识。授权失败尤其是你的预警信号:一个正常的集成几乎不会产生它们,所以一串密集的授权失败意味着有人正在试探。

不要把敏感值本身写进日志。令牌、卡号和个人数据一旦进入日志文件,就会把一次被控制住的泄露,变成一次必须上报的泄露。

对模式告警,而不是对总量告警。一个调用方在大量对象标识符上产生授权失败,说明枚举正在进行,这值得把人从床上叫起来;总体错误率则不值得。

保留时间要长到有用为止。入侵常常在开始数周之后才被发现,而三十天的日志往往太短,不足以找到最初的入口。


去测试你真正发布出去的那套 API

Mecanik 提供应用安全测试 ,重点放在自动化工具漏掉的授权与业务逻辑缺陷上,其中包括使用多个角色的真实凭据进行跨账户测试。

我们从你的规格说明和文档出发,而不是靠猜测攻击面,因此顺带就会发现没有文档的端点和被落下的旧版本。当工作延伸到基础设施与网络测试时,我们的渗透测试服务 覆盖那一块。如果你还在设计 API,我们关于定制 API 开发成本 的指南讲清楚了授权、速率限制和日志应该放在构建的哪个位置,而不是事后补装。

把规格说明和角色描述发给我们,我们会告诉你风险集中在哪里。


相关文章: 英国渗透测试 - 2026年应期待什么2026年英国开发者GDPR技术合规指南Cloudflare Zero Trust:企业访问安全指南为企业主讲解 OWASP Top 10


常见问题

最常见的 API 安全漏洞是什么? 是对象级授权失效,也就是一个已通过身份验证的调用方,只要改掉请求里的一个标识符,就能读到另一位用户的数据。身份验证本身运行正常,但没有任何环节校验被请求的对象是否属于该调用方。因此所有权必须在查询本身里强制执行。

只用 API 密钥的安全性够吗? 单靠它并不够。永不过期的长期密钥会把任何一次泄露变成永久性入侵。请使用带刷新机制的短期访问令牌,按调用方实际需要收窄作用域,支持不停机轮换,并且始终通过请求头而不是 URL 传递它们。

自动扫描能保障 API 安全吗? 不能,但仍然值得持续运行。扫描器能找出已知有漏洞的依赖、缺失的响应头和明显的注入。它们无法理解你的业务规则,因此会漏掉折扣叠加、免费套餐下可访问的付费功能,以及跨账户的数据访问。

API 渗透测试的费用是多少? 一个小而文档齐备的 API 通常从约 £3,000 起,一个角色众多、集成众多的大面积接口则可达 £15,000 甚至更高。费用主要取决于端点数量、不同角色的数量,以及是否提供文档和凭据。

出于安全目的,API 应该记录什么? 身份验证事件、授权失败,以及每一次改变状态的操作,每条都要带上调用方身份、目标对象和一个关联标识。永远不要记录令牌或个人数据。当一个调用方在大量标识符上产生授权失败时应当告警,那说明枚举正在进行。