必须使用具体源而非通配符*,因浏览器强制要求带credentials的跨域请求中access-control-allow-origin精确匹配origin头,否则静默拦截响应;需动态匹配$http_origin并配合白名单校验、options预检处理及credentials头一致设置。

当客户端发起带 credentials: 'include'(比如携带 Cookie、HTTP 认证信息或 TLS 客户端证书)的跨域请求时,浏览器会强制要求服务端返回的 Access-Control-Allow-Origin 值**必须是具体、精确匹配的源**,而不能是通配符 *。这是浏览器安全策略的硬性限制,不是 Nginx 的配置问题,也无法绕过。
为什么 * 和 credentials 不兼容
因为 * 表示“允许任意源”,而 credentials 涉及用户敏感身份凭证。如果两者同时允许,攻击者可构造恶意页面,用用户已登录的 Cookie 向你的 API 发起静默请求(CSRF 变种),造成严重安全风险。浏览器为防此类漏洞,直接拒绝响应——即使 Nginx 返回了 200 和 Set-Cookie,前端 JS 也拿不到响应体,fetch 或 XMLHttpRequest 会报错。
正确处理带 credentials 的跨域请求
-
Origin 必须动态匹配
$http_origin:Nginx 需根据实际请求头中的Origin值,原样回传(协议+域名+端口完全一致)。例如前端发自https://admin.example.com:3000,Nginx 就必须返回Access-Control-Allow-Origin: https://admin.example.com:3000。 -
明确开启凭证支持:添加
add_header 'Access-Control-Allow-Credentials' 'true';,且该头必须出现在所有相关响应中(包括预检和正式请求)。 -
预检请求(OPTIONS)也要严格匹配:不能只在主 location 加头,必须单独拦截 OPTIONS 方法,并同样使用
$http_origin设置Access-Control-Allow-Origin,否则预检失败,后续请求根本不会发出。 -
避免后端覆盖响应头:若 Nginx 是反向代理,确保后端服务不自行设置
Access-Control-Allow-Origin,否则可能被后端头覆盖,导致不一致。
推荐的安全配置方式
使用 map 指令建立白名单,既保证安全性,又防止非法 Origin 被放行:
在 http 块中定义:
map $http_origin $cors_origin {<br> default "";<br> "https://app.example.com" "https://app.example.com";<br> "https://dashboard.example.org" "https://dashboard.example.org";<br> "http://localhost:3000" "http://localhost:3000";<br>}
在 location 块中使用:
if ($cors_origin) {<br> add_header 'Access-Control-Allow-Origin' $cors_origin;<br> add_header 'Access-Control-Allow-Credentials' 'true';<br> add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';<br> add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With';<br>}
if ($request_method = 'OPTIONS') {<br> add_header 'Access-Control-Allow-Origin' $cors_origin;<br> add_header 'Access-Control-Allow-Credentials' 'true';<br> add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';<br> add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With';<br> add_header 'Access-Control-Max-Age' 1728000;<br> add_header 'Content-Type' 'text/plain; charset=utf-8';<br> add_header 'Content-Length' 0;<br> return 204;<br>}
常见错误与规避
- 直接写
add_header 'Access-Control-Allow-Origin' '*';并加Allow-Credentials true→ 浏览器直接拒绝,控制台报 CORS 错误。 - 用
$http_origin却没做白名单校验 → 攻击者可伪造任意 Origin 头,造成开放重定向式跨域漏洞。 - 只在主 location 加头,忽略 OPTIONS 处理 → 预检失败,POST/PUT 等非简单请求发不出去。
- 在 proxy_pass 后端响应中重复加 CORS 头 → 可能因 header 冲突或覆盖导致行为不可控。











