简介
跨源资源共享(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 方法(GET、POST 等)。 |
Access-Control-Allow-Headers | 定义允许的请求标头(Authorization、Content-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 交互至关重要。通过:
- 严格配置允许的源。
- 正确处理预检请求。
- 使用 API 网关实现可扩展性。
