为独立开发者设计“Just Enough” API 安全
Source: Dev.to
不要追求完美。
分层保护你的 API。
为什么 API 安全对独立开发者来说很难
- 无限的攻击面: 一旦你开始考虑安全,可能的攻击列表就永无止境。
- 焦虑循环: “如果发生这种攻击怎么办?” → “那这种情形呢?” → 难以继续前进。
- 资源有限: 你只能管理有限数量的防御措施,所以需要明确的边界。
定义范围
在实现任何东西之前,我问自己:
- 我会考虑的 – 必须防御的威胁。
- 我会有意忽略的 – 对于个人项目而言超出范围的攻击。
这不是正式的威胁模型;它在构建 API 的过程中逐步形成。
需要防护的内容
- 未经身份验证的请求
- 无效或格式错误的参数
- 使用被窃取或重放的 JWT 的请求
需要忽略的内容
- 客户端代码的绝对保密
- 对原生应用进行完整逆向工程的防御
- 仅在 API 层阻止所有可能的攻击
分层安全方法
我将职责分配到三个层级。没有任何单一层级被完全信任。
第 1 层 – 客户端
- JWT 用于用户身份验证
- Signature(HMAC)用于应用程序标识
第 2 层 – API(Cloudflare Workers + Hono)
- 应用程序验证(请求签名)
- JWT 验证与用户识别
- 基础请求验证(方法、路径、参数)
- 轻量级速率限制
第 3 层 – 数据库(Supabase)
- 行级安全(RLS)以强制每个用户的数据隔离
规则: 即使 API 被绕过,其他用户的数据也绝不能被访问。Supabase 的 RLS 在数据库层面强制执行此规则。
应用层验证
为了验证调用方应用,我使用请求签名(HMAC),但 刻意避免:
- 对请求体进行签名
- 严格的 nonce 管理
- 完全的重放防护
相反,我仅对以下内容进行签名:
timestamp(时间戳)- HTTP
method(方法) - 请求
path(路径)
这种权衡在实现成本、运维复杂度和实际威胁等级之间取得了平衡。由于密钥存放在客户端(React Native)中,针对单人开发的完整 HMAC 级别严谨性并不现实。
相关文章: Protecting the API Entry Point with Cloudflare Workers
日志记录与可观测性
- 每个请求都会分配一个唯一的
requestId。 - 日志采用结构化 JSON,便于聚合。
- 向客户端返回的错误响应保持最小化;内部日志能够清晰地区分身份验证失败和授权失败。
- 在演示中日志输出到控制台,但将输出切换到生产级日志记录器非常简单。
步骤式设计流程
对我而言效果最好的顺序:
- 修正假设 – 确定客户端和用户。
- 决定威胁边界 – 必须保护的内容与可以忽略的内容。
- 锁定数据库 – 启用 RLS(行级安全)以防止跨用户访问。
- 确认用户身份 – 实现 JWT 认证。
- 在 API 入口处验证请求 – 基础校验,拒绝异常流量。
- 如有需要添加应用层标识 – 签名 / 时间戳。
- 限制意外的请求突发 – 速率限制。
- 使问题可追踪 –
requestId与结构化日志。
按照这个顺序,我得到了一个 既不过度设计,又不易被意外破坏 的 API 设计。
演示仓库
完整的演示可在以下位置找到:
相关文章: 我如何设计 Supabase 和行级安全 (RLS)
结论
从第一天起就“正确”地设计安全性极其困难,尤其是当你独自工作时。通过:
- 设定明确的边界,
- 分层防御,以及
- 将可观测性视为一等重要的关注点,
你可以实现“恰到好处”的安全性,而不会在复杂性中溺亡。希望本文能帮助你决定自己的 API 安全应当做到何种程度。