你的 API 默认公开 — 让我们来修复它

发布: (2026年2月3日 GMT+8 16:47)
6 min read
原文: Dev.to

Source: Dev.to

这里有一个令人毛骨悚然的想法:除非你主动将其设为私有,否则你部署的每个 API 默认都是公开的。大多数后端泄露并非来自顶级黑客,而是源于无聊的脚本、泄露的令牌,或是你忘记存在的端点。让我们一起梳理一下我在生产环境中仍然常见的 API 安全错误——以及如何在不把后端变成可用性噩梦的前提下加固它。

Authentication vs. Authorization

Authentication 回答 你是谁
Authorization 回答 你被允许做什么

许多 API 只停留在身份验证。

GET /api/users/123
Authorization: Bearer <token>

如果令牌有效,请求会成功——即使用户不应该看到该数据。

// ❌ 只检查身份验证
if (!req.user) throw new UnauthorizedError();

// ✅ 检查授权
if (req.user.id !== params.userId && !req.user.isAdmin) {
  throw new ForbiddenError();
}

安全经验法则: 每一次读取、写入和删除都必须回答“为什么允许该用户?”

JWT 陷阱

JWT 很棒,但被误用的 JWT 危险。

常见问题

  • 没有过期时间 (exp)
  • 令牌存储在 localStorage
  • 用户注销后令牌被永久接受
  • 没有受众 (aud) 或发行者 (iss) 验证
const payload = jwt.verify(token, JWT_SECRET, {
  audience: 'api.myapp.com',
  issuer: 'auth.myapp.com',
});

最佳实践

  • 短期访问令牌(5–15 分钟)
  • 刷新令牌存储为 httpOnly
  • 刷新时进行令牌轮换

JWT 本身并不能让你安全——是你的验证逻辑保证安全。

限流

如果你的 API 包含登录、OTP、密码重置、搜索、公共端点……它就需要限流。没有例外。

为什么重要

  • 没有限制,暴力破解攻击变得轻而易举
  • 爬虫会消耗你的带宽
  • 一个不良客户端就能对你的系统进行 DOS
import rateLimit from 'express-rate-limit';

export const limiter = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 100,            // requests per minute
});

对以下情况应用不同的限制:

  • 认证端点
  • 公共 API
  • 内部服务

安全不是阻止用户,而是控制滥用。

最小化数据暴露

常见的真实世界泄露案例:

{
  "id": 42,
  "email": "user@example.com",
  "passwordHash": "...",
  "isAdmin": false,
  "createdAt": "..."
}

没有人想要暴露 passwordHash

安全的 DTO

// ✅ Safe DTO
return {
  id: user.id,
  email: user.email,
  createdAt: user.createdAt,
};

切勿依赖:

  • ORM 默认序列化 (res.json(entity))
  • “我们将在前端过滤”

如果你没有将字段列入白名单,它就不应该离开服务器。

CORS 误解

“没问题,我们的 CORS 已经锁定。”

CORS 只影响浏览器。它 不会 阻止:

  • 服务器之间的调用
  • 机器人、移动应用、Postman、curl
curl https://api.yoursite.com/secret

CORS 的目的是 防止恶意网站滥用用户的浏览器,而不是用来保护你的 API。

密钥管理

如果你的仓库曾经包含过:

  • .env 文件
  • API 密钥
  • Firebase 配置
  • AWS 凭证

…请假设它们已经泄露。

建议

  • 仅在 环境变量 中存储密钥
  • 定期轮换密钥
  • 永不记录密钥(即使在调试时)
  • 将密钥的权限范围限制到最小

如果密钥泄漏,影响范围应当很小,而不是致命的。

审计与日志

当出现问题时,你需要答案:

  • 谁做的?
  • 何时?
  • 从哪里?
  • 使用了哪个令牌?

如果不记录安全相关的操作,你将一无所知。

记录(但不要过度记录)

  • 认证尝试
  • 权限失败
  • 管理员操作
  • 令牌刷新
  • 角色变更

要有目的性,避免冗长。

微服务与零信任

仅仅因为一个端点:

  • 位于 VPC 后面
  • 在私有子网中
  • “仅被服务调用”

…并不意味着它是安全的。

加固服务间通信

  • 服务间身份验证(例如 mTLS、签名的 JWT)
  • 短期令牌
  • 网络层规则
  • 明确的权限

零信任并非偏执——它是现实。

摘要:一份枯燥而严谨的决策清单

  • 明确授权 for every operation
  • 最小化数据暴露 (whitelist fields)
  • 全局速率限制 (auth, public, internal)
  • 短期凭证 (access & refresh tokens)
  • 清晰的审计日志 (auth, permission, admin actions)

大多数泄露并非源自高级漏洞。它们往往来自你忘记更改的默认设置。实施这些严谨的做法,你将显著降低 API 的攻击面。

Back to Blog

相关文章

阅读更多 »