CORS安全配置指南
目录导读
CORS原理简述
跨域资源共享(Cross-Origin Resource Sharing, CORS)是一种基于HTTP头的安全机制,它允许运行在一个源(domain)上的Web应用访问来自不同源的服务端资源,在Web安全架构中,同源策略(Same-Origin Policy)是默认的安全屏障,它阻止跨域读取资源,CORS提供了一种标准方式,让服务器声明哪些源可以访问其资源。
当浏览器发起跨域请求时,会自动在请求头中添加Origin字段,标明请求来源,服务器根据预定义的规则,在响应头中添加相应的CORS字段(如Access-Control-Allow-Origin),浏览器根据这些响应头决定是否允许前端JavaScript代码访问跨域响应。
CORS请求分为两类:简单请求和预检请求,简单请求满足特定条件(如使用GET、POST、HEAD方法,Content-Type为特定值),浏览器会直接发出请求并在响应中检查CORS头,不满足简单请求条件的请求,浏览器会先发送一个OPTIONS方法的预检请求,确认服务器允许实际请求后,才会发出真正的请求。
服务器端配置详解
正确的CORS配置需要在服务器端进行,以下以常见技术栈为例说明配置方法:
Node.js/Express配置
const express = require('express');
const app = express();
// 基础CORS配置
app.use((req, res, next) => {
// 允许的源列表(生产环境应具体指定)
const allowedOrigins = ['https://ww.jxysys.com', 'https://api.jxysys.com'];
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
}
// 允许的HTTP方法
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
// 允许的请求头
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With');
// 是否允许发送Cookie
res.setHeader('Access-Control-Allow-Credentials', 'true');
// 预检请求缓存时间(秒)
res.setHeader('Access-Control-Max-Age', '86400');
// 允许前端访问的响应头
res.setHeader('Access-Control-Expose-Headers', 'Content-Length, X-Total-Count');
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}
next();
});
Nginx服务器配置
server {
listen 80;
server_name api.jxysys.com;
location / {
# 动态匹配允许的源
if ($http_origin ~* (https://ww.jxysys.com|https://admin.jxysys.com)) {
add_header 'Access-Control-Allow-Origin' "$http_origin";
}
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Max-Age' 86400;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
# 处理预检请求
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' "$http_origin";
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header 'Access-Control-Max-Age' 86400;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
proxy_pass http://backend;
}
}
Apache服务器配置
<IfModule mod_headers.c>
# 设置允许的源
SetEnvIf Origin "^(https?://(ww\.jxysys\.com|api\.jxysys\.com))$" CORS_ALLOW_ORIGIN=$1
Header append Access-Control-Allow-Origin %{CORS_ALLOW_ORIGIN}e env=CORS_ALLOW_ORIGIN
# 允许的方法和头
Header always set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
Header always set Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization"
Header always set Access-Control-Allow-Credentials "true"
Header always set Access-Control-Max-Age "86400"
# 处理OPTIONS请求
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
</IfModule>
CORS配置安全实践
源白名单策略
切勿使用通配符作为Access-Control-Allow-Origin的值,除非是公开的API且不需要凭证,应维护明确的允许源白名单:
// 安全做法:验证源是否在白名单中
const allowedOrigins = new Set([
'https://ww.jxysys.com',
'https://app.jxysys.com',
'https://admin.jxysys.com'
]);
const requestOrigin = req.headers.origin;
if (allowedOrigins.has(requestOrigin)) {
res.setHeader('Access-Control-Allow-Origin', requestOrigin);
}
凭证与安全配置
当请求需要携带Cookie或HTTP认证信息时,必须谨慎配置:
- 设置
Access-Control-Allow-Credentials: true时,Access-Control-Allow-Origin不能为通配符 - 前端需要在请求中设置
withCredentials: true - 考虑实施CSRF令牌等额外保护措施
减少暴露头信息
仅暴露必要的响应头,避免泄露敏感信息:
// 只暴露必要的头信息
res.setHeader('Access-Control-Expose-Headers', 'X-Pagination-Total, X-RateLimit-Limit');
预检请求优化
合理设置Access-Control-Max-Age缓存预检请求,减少不必要的OPTIONS请求:
- 开发环境可设置较短时间(如300秒)
- 生产环境可设置较长时间(如86400秒)
- 注意缓存时间过长可能导致配置更新不及时
生产环境监控
- 监控异常的CORS请求,特别是来自未知源的请求
- 定期审计CORS配置,确保与业务需求一致
- 实现CORS配置的版本控制和自动化测试
常见问题与解答
Q1: 为什么CORS配置在生产环境中特别重要?
CORS配置不当可能导致严重的安全漏洞,过于宽松的CORS策略可能使攻击者能够从恶意网站访问您的API,窃取用户数据或执行未授权操作,正确的CORS配置是Web应用安全防护的重要组成部分。
Q2: 如何处理多个子域名的CORS配置?
对于拥有多个子域名的应用(如ww.jxysys.com、api.jxysys.com、app.jxysys.com),可以采用以下策略:
- 维护完整的子域名白名单
- 使用正则表达式匹配允许的域名模式
- 考虑使用通配符子域名(如
*.jxysys.com),但需注意浏览器兼容性和安全风险
Q3: 预检请求失败常见原因有哪些?
预检请求失败通常由以下原因导致:
- 服务器未正确处理OPTIONS方法请求
Access-Control-Allow-Headers未包含实际请求中的所有头Access-Control-Allow-Methods未包含实际请求方法- 当使用凭证时,
Access-Control-Allow-Origin设置为通配符
Q4: 如何测试CORS配置是否正确?
可通过以下方式测试CORS配置:
- 使用浏览器开发者工具查看网络请求和响应头
- 编写测试脚本模拟不同源的请求
- 使用在线CORS测试工具
- 实施自动化测试,确保配置变更不会破坏现有功能
Q5: CORS与JSONP有什么区别?
CORS是现代浏览器支持的官方标准,支持各种HTTP方法和请求类型,安全性更好,JSONP是传统跨域技术,只支持GET请求,存在安全隐患(如XSS风险),新项目应优先使用CORS,仅在需要支持非常旧的浏览器时才考虑JSONP。
正确的CORS配置需要在便利性和安全性之间找到平衡点,过于严格的配置可能影响合法功能,过于宽松的配置则带来安全风险,建议采用最小权限原则,仅允许必要的源、方法和头,并定期审查和更新配置以适应业务变化,通过合理配置CORS,可以在确保Web应用安全的同时,提供良好的跨域资源共享体验。
