API 101 专栏 · 第 25

API 中的 CORS:处理跨源请求

2025年06月11日
API 中的 CORS:处理跨源请求

简介

跨源资源共享(CORS)是一种安全机制,允许 Web 应用程序安全地从不同域名请求资源。由于 API 为现代 Web 和移动应用程序提供支持,因此正确处理 CORS 对于实现无缝的功能和安全性至关重要。

为什么你应该关注 CORS?

  • 防止未经授权的跨源请求,降低安全风险。
  • 确保正常的前后端通信(例如,React 应用调用后端 API)。
  • 错误配置的 CORS 策略可能会破坏应用程序或暴露漏洞。

在本指南中,我们将探讨 CORS 的工作原理、最佳实施实践、安全注意事项以及实际的故障排除技巧——帮助 API 开发者和网关管理员有效地管理 CORS。

什么是 CORS?

1. 定义与目的

同源策略(SOP)限制网页向不同的源(域名、协议或端口)发出请求。CORS 通过允许明确许可的跨源请求,安全地放宽了这些限制。

常见用例:

  • React 应用(https://app.example.com)访问 API(https://api.example.com)。
  • 第三方集成(例如,在 SaaS 应用中嵌入外部 API)。

2. CORS 的工作原理

CORS 引入了 HTTP 标头(Headers)来控制访问:

标头 (Header)目的
Access-Control-Allow-Origin指定哪些源可以访问资源(* 或特定域名)。
Access-Control-Allow-Methods列出允许的 HTTP 方法(GETPOST 等)。
Access-Control-Allow-Headers定义允许的请求标头(AuthorizationContent-Type 等)。
Access-Control-Expose-Headers指定客户端可以访问哪些响应标头。
Access-Control-Allow-Credentials决定是否可以包含凭据(Cookie、身份验证令牌)。

浏览器与服务器交互流程:

1sequenceDiagram
2    Browser->>Server: OPTIONS 预检请求 (Preflight Request)
3    Server-->>Browser: 响应允许的方法/标头
4    Browser->>Server: 实际请求 (GET/POST/等)
5    Server-->>Browser: 返回带有 CORS 标头的数据
  • 简单请求:(例如,带有标准标头的 GET 请求)跳过预检。
  • 预检请求(OPTIONS):在实际请求之前验证权限。

常见的 CORS 问题与挑战

错误配置的 CORS 可能会阻止合法请求或暴露安全风险。

因缺少标头导致请求被阻止

示例:

1Access to fetch at 'https://api.example.com' from origin 'https://client.com' has been blocked by CORS policy.

原因:响应中缺少 Access-Control-Allow-Origin

凭据与通配符 (*) 冲突

1Access-Control-Allow-Origin: *  // 如果使用 Cookie/身份验证令牌,则会失败

修复:明确指定允许的域名,而不是使用 *

预检失败

  • 缺少对 OPTIONS 方法的支持。
  • 请求的标头未在 Access-Control-Allow-Headers 中列出。

真实数据:

  • 62% 与 API 相关的 CORS 问题源于预检处理配置错误(来源:StackOverflow Dev Survey 2023)。

3. 在 API 中实现 CORS

3.1 后端示例

Node.js (Express):

1app.use((req, res, next) => {
2  res.setHeader('Access-Control-Allow-Origin', 'https://client.com');
3  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
4  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
5  res.setHeader('Access-Control-Allow-Credentials', 'true');
6  next();
7});

Python (Flask):

1from flask_cors import CORS  
2CORS(app, origins=["https://client.com"], supports_credentials=True)

API 网关(APISIX 示例):

1plugins:
2  cors:
3    allow_origins: "https://client.com"
4    allow_methods: "GET,POST,OPTIONS"
5    allow_headers: "content-type,authorization"

3.2 网关层 CORS 的优势

  • 集中管理(避免代码重复)。
  • 性能优化(例如,缓存预检响应)。

API 中 CORS 的最佳实践

  • 限制允许的源(在生产环境中避免使用 *)。
  • 缓存预检响应:
1Access-Control-Max-Age: 86400  // 24 小时缓存
  • 限制暴露的标头:
1Access-Control-Expose-Headers: X-Custom-Header

关键安全提示:

  • 始终在服务器端验证 Origin 标头,以防止欺骗。
1flowchart LR  
2    A[传入请求] --> B{Origin 有效?}
3    B -->|是| C[处理请求]  
4    B -->|否| D[阻止请求]  

调试 CORS 问题

  • 浏览器开发者工具:在“网络”(Network)选项卡下检查失败的请求。
  • 使用 cURL 进行测试:
1curl -H "Origin: https://client.com" -I https://api.example.com
  • 常见错误与修复方法:
错误解决方案
No 'Access-Control-Allow-Origin' header将标头添加到服务器响应中。
Preflight missing OPTIONS确保服务器处理 OPTIONS 方法。

安全注意事项

  • 过于宽松的 CORS → CSRF / 数据窃取风险。
  • 避免:
1Access-Control-Allow-Origin: *
2Access-Control-Allow-Credentials: true  // 不安全的组合!
  • 对于敏感端点,将 CSRF 令牌与 CORS 结合使用。

总结

CORS 对于安全的跨源 API 交互至关重要。通过:

  1. 严格配置允许的源。
  2. 正确处理预检请求。
  3. 使用 API 网关实现可扩展性。

微信咨询

获取方案