AllowOrigins: ["*"] 在生产环境不安全,因它放行任意域名请求,且与 AllowCredentials: true 冲突导致预检失败;攻击者可借恶意页面窃取敏感数据;Origin 是协议+域名+端口组合,IP 无效;应显式列出可信前端地址,禁用通配符和 glob;动态校验需手写中间件,确保 OPTIONS 返回 204 且头设置正确;开发与生产配置须严格分离。

为什么 AllowOrigins: ["*"] 在生产环境不安全
浏览器允许 Access-Control-Allow-Origin: "*",但前提是不能同时设置 Access-Control-Allow-Credentials: "true"。一旦后端启用了 Cookie 或 Authorization 携带(比如登录态),"*" 就会被浏览器直接拒绝,预检失败。更关键的是:它完全放行任意域名发起的请求,攻击者可构造恶意页面诱导用户访问,再通过 JS 调用你的 API 窃取敏感数据(如用户信息、Token)。IP 地址本身不是 Origin,Origin 一定是 协议 + 域名 + 端口 组合,所以“校验 IP”在 CORS 规范里无意义——你真正要控制的是 Origin 字符串是否可信。
如何用 gin-contrib/cors 安全地限制来源
必须显式列出合法前端地址,禁止使用通配符。常见错误是写成 ["https://*.example.com"],该库不支持 glob 或正则匹配,只会做字符串精确比对或前缀匹配(且前缀匹配需手动开启)。
- ✅ 正确写法:
[]string{"https://admin.example.com", "https://app.example.com:8080"} - ❌ 错误写法:
["*"]、["https://*.example.com"]、["https://example.com"](漏了www.或端口) - ⚠️ 注意:HTTP 和 HTTPS 视为不同源,
http://localhost:3000和https://localhost:3000必须分别列出
动态 Origin 校验:自己写中间件才可控
当需要根据请求头中的 Origin 做白名单校验(比如从数据库查出当前租户允许的域名),gin-contrib/cors 不适用。必须手写中间件,在 c.Next() 后设置响应头,并确保 OPTIONS 请求能正常返回 204。
- 先读取
c.Request.Header.Get("Origin"),空值或非法格式直接跳过设头 - 用
strings.HasPrefix()或map[string]bool白名单快速判断是否允许 - 只对合法 Origin 设置
c.Header("Access-Control-Allow-Origin", origin),不要设成"*" - 务必在
if c.Request.Method == "OPTIONS" { c.AbortWithStatus(204); return }前完成所有头设置,否则预检会失败
开发期 vs 生产期配置差异容易踩的坑
本地开发常用 http://localhost:3000,但生产环境是 https://app.example.com,二者协议、域名、端口都不同。若 config.yaml 或中间件里混用,上线后立刻跨域失败。
- 开发配置示例:
allowOrigins: ["http://localhost:3000", "http://localhost:8080"] - 生产配置示例:
allowOrigins: ["https://admin.example.com", "https://api.example.com"] - 别把开发配置打包进生产镜像;用环境变量或配置中心区分
-
AllowCredentials: true时,AllowOrigins列表中绝对不能含"*",哪怕只有一项也不行
www 子域、没处理 HTTP/HTTPS 混合、OPTIONS 响应体非空(导致浏览器拒收),以及把中间件注册在了路由注册之后——这会让部分路由绕过 CORS 控制。


















