← 返回博客

API 安全实战:认证、授权与常见攻击防护

API 安全不是"加个 Token 就行"。本文从认证与授权的基础模型出发,讨论 JWT 与 Session 的选型、OAuth 2.0 的四种授权流程、以及 SQL 注入、XSS、CSRF、DDoS 等常见攻击的防御策略——适合正在搭建或审查 API 安全体系的后端开发者和架构师。

先说结论:API 安全不是”加个 Token 就行”

很多团队在 API 开发初期对安全的投入只有”加个 Token 验证”,等到上线后出现数据泄露、接口被刷、恶意爬取时才回头补课。但安全不是补丁,是设计阶段就该考虑的结构性问题。

本文从三个层面展开:认证与授权、常见攻击防护、安全配置清单。


1. 认证与授权

1.1 认证方式选型

方式优点缺点适用场景
JWT无状态,跨服务共享,不依赖存储无法主动撤销,Payload 不过大微服务、对外 API
Session可主动登出,服务端完全控制需要集中存储,跨服务需共享 Session单体、管理系统
API Key简单,适合机器间通信粒度粗,只能识别应用不能识别用户第三方集成、开放 API

推荐实践:对外 API 用 JWT + 短期过期(15-60 分钟),配合 Refresh Token 实现无感续期。对内管理系统用 Session + Redis 存储,支持主动登出和权限回收。

1.2 OAuth 2.0 授权流程

如果你的 API 需要授权第三方访问用户数据,OAuth 2.0 是标准方案。四种授权流程对应不同场景:

Authorization Code(授权码)     → 第三方应用访问用户数据(最常用)
Client Credentials(客户端凭证) → 服务间通信(无需用户授权)
Resource Owner Password(密码)  → 第一方应用登录(不推荐,除非高度信任)
Implicit(隐式)                 → 已废弃,改用 PKCE

对于大多数场景,只需要 Authorization Code + PKCE 这一种流程就够了。

1.3 权限模型

API 级别的权限控制建议用 RBAC(基于角色的访问控制)

// 用户 → 角色 → 权限
{
  "userId": 1,
  "roles": ["admin", "editor"],
  "permissions": ["post:create", "post:edit", "user:delete"]
}

中间件在每个需要鉴权的接口检查权限:

function requirePermission(perm: string) {
  return (req, res, next) => {
    if (!req.user.permissions.includes(perm)) {
      return res.status(403).json({ error: 'forbidden' });
    }
    next();
  };
}

2. 常见攻击与防御

2.1 SQL 注入

虽然 ORM 框架的普及使 SQL 注入减少,但在 ORDER BY 子句、动态表名、LIKE 查询中仍然存在。

防御:任何时候使用参数化查询,不拼接 SQL 字符串。

// ❌ 错误
const sql = `SELECT * FROM users WHERE name = '${name}'`;

// ✅ 正确
const sql = 'SELECT * FROM users WHERE name = $1';

2.2 XSS(跨站脚本攻击)

当 API 返回用户输入的内容(如评论、个人简介)时,如果未做转义,攻击者可以注入脚本。

防御:API 返回用户输入内容时做 HTML 转义,或使用 Content-Type: application/json 确保浏览器不会将响应解析为 HTML。

2.3 CSRF(跨站请求伪造)

攻击者诱导用户在已登录状态下访问恶意链接,利用用户的登录态执行非预期操作。

防御:使用 SameSite Cookie 属性(SameSite=StrictSameSite=Lax),或要求每个写操作请求携带 CSRF Token。

2.4 限流与防刷

API 接口暴露后,没有限流保护就是敞开了让人刷。

分层限流策略

网关层:按 IP 全局限流          → 100 req/min/IP
应用层:按用户 ID 细粒度限流     → 10 req/min/user(写操作)
核心接口:登录/注册/密码重置      → 5 req/min/IP

用 Redis 实现滑动窗口计数器:

async function rateLimit(key: string, limit: number, window: number): Promise<boolean> {
  const current = await redis.incr(key);
  if (current === 1) await redis.expire(key, window);
  return current <= limit;
}

2.5 HTTPS

所有生产环境的 API 必须强制 HTTPS。在代码层面拒绝 HTTP 请求:

if (req.headers['x-forwarded-proto'] !== 'https') {
  return res.redirect(301, `https://${req.headers.host}${req.url}`);
}

3. 安全配置清单

类别检查项说明
传输层HTTPS 强制301 跳转 + HSTS 头
认证Token 过期JWT 过期时间 ≤ 60 分钟
授权接口级权限校验每个接口检查当前用户是否有对应权限
输入参数化查询所有数据库操作禁止拼接 SQL
输出HTML 转义用户输入内容返回前做转义
请求限流分层限流(网关+应用+核心接口)
请求CORS 白名单只允许可信任的域名跨域访问
响应安全头X-Frame-Options、X-Content-Type-Options、Referrer-Policy

API 安全不是一次性投入——每次新增接口、每次升级依赖,都是重新审视安全配置的机会。 把安全清单纳入 Code Review 和 CI 检查,比等出了问题再补救成本低得多。

需要后端 API 开发或安全审计服务?联系我们,说清你的接口场景与规模,24 小时内回可行性。

相关阅读

常见问题

JWT 和 Session 认证怎么选?

JWT 适合无状态、跨服务的场景(如微服务之间传递身份信息),但不支持服务端主动登出,Token 泄露后无法撤销。Session 适合单体或可以通过集中 Session 存储的服务,支持主动登出,但需要额外的存储层(Redis/DB)。建议:对外 API 用 JWT 配合短期过期时间(15-60 分钟),对内管理系统用 Session。

API 需要 HTTPS 吗?

需要。HTTPS 不仅加密传输内容防止中间人攻击,还提供了身份验证(确保你在和真正的服务器通信)和数据完整性(确保传输内容未被篡改)。没有 HTTPS 的 API,Token 和密码在网络传输中是明文,抓包就能看到。所有生产环境的 API 都应该强制 HTTPS,并在代码层面拒绝 HTTP 请求。

SQL 注入现在还有用吗?

有用。虽然 ORM 框架的普及减少了 SQL 注入的发生概率,但只要还存在原生 SQL 拼接(尤其是 ORDER BY 子句、动态表名、LIKE 查询),SQL 注入就没有消失。防御手段只有一条:永远不要拼接 SQL 字符串,任何时候都使用参数化查询或预编译语句。

API 的限流应该怎么做?

分层限流:① 网关层按 IP 和 API Key 做全局限流(如每 IP 每分钟 100 次);② 应用层按用户 ID 做更细粒度的限流(如每用户每分钟 10 次写操作);③ 核心接口做针对性限流(如登录接口每 IP 每分钟 5 次)。工具上可以用 Redis 的 INCR + EXPIRE 实现滑动窗口计数器,或用 Nginx 的 limit_req 模块做简单限流。

本文来自 AI Enable Harness 一线交付实践。需要同类系统或优化服务?

订阅博客更新

新文章发布后第一时间邮件通知。不定期发送,不推销。

订阅 →