💡 Key Takeaways
- Authentication and Authorization: The Foundation That Everyone Rushes Past
- Request Validation: Where Most Bugs Actually Live
- Response Validation: Trust, But Verify
- State Management and Idempotency: The Subtle Art of Consistency
三年前,我在凌晨两点目睹了一次生产API的失败,原因是没有人测试当你发送一个格式为“32/13/2021”的日期字段时会发生什么。这个崩溃的连锁反应在最糟糕的方式中是美丽的:47,000笔交易失败,愤怒的客户涌入支持渠道,还有一位想要答案的CEO,而我没有任何答案。那晚彻底改变了我对API测试的看法。
💡 关键要点
- 身份验证和授权:每个人匆匆而过的基础
- 请求验证:大多数错误实际存在的地方
- 响应验证:信任但要验证
- 状态管理与幂等性:一致性的微妙艺术
我叫Sarah Chen,过去八年我一直是QA自动化工程师,最后五年专注于金融科技和医疗平台的API测试。我测试过从简单的CRUD端点到处理每日数百万美元的复杂支付处理API。我所学到的是:大多数API故障并不是奇特的边缘案例——而是可以预测的问题,系统的检查表可以抓到它们。
我今天分享的检查表就是我在测试每一个端点时使用的那个。仅在过去一年中,它救了我的团队免于至少十几次生产事故,并帮助我们在230多个API端点上保持了99.97%的正常运行时间。这不是理论——这是来自于一个在凌晨三点被叫醒次数太多的人的实战经验。
身份验证和授权:每个人匆匆而过的基础
有一个统计数字应该让你感到恐惧:根据我在七家不同公司审计API的经验,大约60%至少有一个端点存在授权逻辑错误。不是身份验证——是授权。该端点验证了你已登录,但没有正确检查你是否应访问该特定资源。
我的身份验证和授权检查表从明显但常被忽略的基础开始:
- 测试完全没有身份验证令牌——应返回401
- 测试过期令牌——应返回401,而不是500
- 测试格式错误的令牌——应返回401,而不是崩溃
- 测试有效令牌但权限错误——应返回403
- 测试其他用户的令牌试图访问其他用户的资源
最后一个就是事情变得有趣的地方。我曾找到一个端点,你只需在URL中更改用户ID,就可以检索任何用户的付款历史,即使你是以不同用户的身份进行身份验证。该端点检查你是否已登录,但从未验证请求的用户ID是否与你已验证的用户ID匹配。这称为不安全的直接对象引用(IDOR),而且它令人震惊地常见。
我还专门测试令牌刷新流程。当令牌在请求中间过期时会发生什么?你的API是否优雅地处理了这个情况,还是让客户端处于奇怪的状态?我见过有些系统,在POST请求期间过期的令牌会返回401,但数据仍然部分写入数据库。这对数据一致性来说是一个噩梦。
对于使用API密钥而不是令牌的API,我会确认密钥轮换是否正常工作。你能生成一个新密钥吗?旧密钥是否立即停止工作,还是有一个宽限期?那个宽限期是否有文档?我曾经与一个API合作过,在那里轮换密钥有一个24小时的重叠期,而没有人知道,这导致了安全审计失败。
授权矩阵是我在这里的秘密武器。我创建了一个电子表格,在一个轴上列出每个端点,在另一个轴上列出每个用户角色。然后我系统地测试每种组合。这很乏味,但在我应用它的100%的项目中,它捕捉到了授权错误。是的,100%。这不是夸张——每个项目都有至少一个端点的授权逻辑对至少一个角色是错误的。
请求验证:大多数错误实际存在的地方
如果我得猜测70%的API错误来源于哪里,那就是请求验证。开发人员是乐观的生物——他们编写代码时假设输入是合理的。但是互联网并不合理,调用你的API的系统也不合理。
我的请求验证检查表是详尽无遗的,因为它需要如此:
- 发送完全空的请求体——会发生什么?
- 逐个为每个必填字段发送空值
- 为字符串字段发送空字符串
- 发送仅包含空格的字符串
- 发送字符串长度超过任何长度限制的字符
- 发送长度是1000倍过长的字符串
- 发送期望正整数字段的负数
- 发送零的字段,其中零可能是无效的
- 发送应为整数字段的小数
- 发送极大的数字(测试整数溢出)
- 发送极小的数字(测试欠流)
- 在字符串字段中发送特殊字符:引号、反斜杠、空字符、Unicode
- 发送SQL注入尝试(即使你在使用ORM)
- 在字符串字段中发送XSS有效负载
- 发送不匹配的数据类型(字符串应为数字时等)
我知道你在想什么:“Sarah,这太疯狂了。没有人有时间做这些。”但是——我已经将整个检查表自动化了。我有一个测试数据生成器可以自动产生所有这些变体。最初的设置花费了我大约两周的时间,但现在我可以在大约15分钟内针对一个新端点运行整个测试套件。
回报是真实的。上个月,这个检查表捕捉到了一个在你发送超过65,535个字符的字符串时会崩溃整个API服务器的端点。开发人员以为数据库会处理长度验证,但数据库被配置为静默截断,而应用程序代码试图将整个字符串记录到固定大小的缓冲区。砰——段错误,服务器崩溃。
对于日期和时间字段,我有一个特殊的子检查表,因为这些是独特的糟糕:
- 发送不同格式的日期(ISO 8601,MM/DD/YYYY,DD/MM/YYYY等)
- 发送无效日期(2月30日,月份13,日期32)
- 发送很久以前的日期(1900年,公元1年)
- 发送很久以后的日期(2100年,9999年)
- 发送具有不同时区偏移的日期
- 发送在夏令时转换期间的日期
- 发送毫秒、微秒、纳秒的时间戳
那个有关夏令时的测试让我遇到过两次麻烦。两次!你会想我会学到教训,但这是一种奇怪的边缘案例,很容易忘记。我现在有一个特定的测试,在钟表变更的那天上午2点运行交易,因为那时会发生奇怪的事情。
响应验证:信任但要验证
大多数测试人员非常关注请求,几乎不关注响应。恰恰相反。您的API的响应是它与世界的合同。如果它们不一致、不完整或不正确,您就破坏了该合同。
| 测试类别 | 常见失败点 | 预期响应 | 实际发生的情况 |
|---|---|---|---|
| 没有身份验证令牌 | 缺少错误处理 | 401 未授权 | 500 内部服务器错误或泄露数据 |
| 过期令牌 | 令牌验证逻辑 | 401 未授权 | 500 错误或静默失败 |
| 格式错误的令牌 | 输入验证 | 401 未授权 | 应用程序崩溃或堆栈跟踪泄露 |
| 有效令牌,权限错误 | 授权检查 | 403 禁止访问 | 200 成功但未经授权的数据访问 |
| 无效的日期格式 | 输入清理 | 400 错误请求 | 交易级联失败 |
我的响应验证检查表包括:
- 验证响应状态代码是否符合文档行为
- 验证响应内容类型头是否正确
- 验证响应体结构是否符合模式
- 验证所有文档字段是否存在
- 验证没有未记录的字段存在(这对API版本化很重要)
- 验证字段数据类型是否符合文档
- 验证字段值是否在文档范围内
- 验证时间戳是否在正确的时区
- 验证分页元数据是否正确且一致
- 验证错误响应是否包含有用的错误信息
- 验证错误响应是否包含可进行编程处理的错误代码
关于错误消息的倒数第二点至关重要。我见过API返回“错误”作为整个错误消息。那是毫无用处的。一个好的错误消息会告诉你出了什么问题、为什么出问题,以及理想情况下你可以做些什么来解决它。比较这两个错误响应:
坏的: {"error": "无效请求"}
好的: {"error": "无效请求", "message": "字段'email'是必填项但未提供", "code": "MISSING_REQUIRED_FIELD", "field": "email"}
第二