你的 API 默认公开 — 让我们来修复它
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 的攻击面。