当前位置: 首页 > backend >正文

跨域问题及其CORS解决方案:gin框架中配置跨域

一、同源策略

浏览器的同源策略(Same-Origin Policy)要求:只有协议、域名和端口都相同的请求才被视为同源,才允许正常访问。

两个URL在以下三个方面完全相同时称为"同源":

  1. 协议相同(如都是http或https)
  2. 域名相同(如都是example.com)
  3. 端口相同(如都是80端口)

二、同源策略的限制

  • 读取非同源的DOM(iframe、窗口等)
  • 发送AJAX请求到非同源地址
  • 读取非同源的Cookie、LocalStorage等存储数据

例如:

  • https://example.com/page1https://example.com/page2 是同源
  • http://example.comhttps://example.com 不同源(协议不同)
  • https://example.comhttps://sub.example.com 不同源(域名不同)
  • https://example.comhttps://example.com:8080 不同源(端口不同)

三、同源策略的作用

**限制跨源DOM访问:**同源策略规定,不同源的页面无法直接访问彼此的DOM。例如,恶意网站 http://malicious.com 无法通过 JavaScript 读取或修改 http://target.com 的表单数据、页面结构或用户输入内容。这从根本上阻止了XSS攻击者窃取敏感信息(如登录凭据)或篡改页面内容。

**隔离Cookie访问:**浏览器仅允许同源页面访问当前域的Cookie。如果没有这一限制,攻击者可以通过恶意脚本窃取目标网站的会话Cookie,从而冒充用户身份。同源策略确保 http://malicious.com 无法读取 http://target.com 的Cookie,防止会话劫持等攻击。

**独立的脚本执行环境:**不同源的JavaScript运行在隔离的上下文中,无法直接访问其他源的全局变量、函数或对象。例如,即使攻击者在目标网站的评论区注入恶意脚本,该脚本也无法绕过同源策略去窃取或篡改主站的关键数据,从而限制了XSS攻击的危害范围。

**严格限制跨域请求:**默认情况下,浏览器禁止脚本发起跨域HTTP请求(如 fetchXMLHttpRequest),除非目标服务器明确允许(如通过CORS)。这一机制防止攻击者将窃取的数据自动发送到恶意服务器,阻断了XSS攻击的数据外泄途径。

可见同源策略主要是在防止跨站脚本攻击(XSS)

四、同源策略的例外

同源策略虽然是Web安全的重要基石,但为了满足实际开发需求,浏览器也提供了一些合理的例外情况:

静态资源加载<script><img><link><video><audio>等标签允许加载跨域资源,静态资源(如图片、视频)通常不包含敏感数据,同时,虽然可以加载,但JavaScript无法读取这些资源的内容(除非CORS允许)。

CORS(跨源资源共享):通过预检请求和特殊响应头实现受控的跨域访问。现代Web应用需要合法的跨域通信(如前后端分离架构),通过服务器显式声明允许的跨域请求,兼顾安全与功能。

使用JSONP技术进行跨域请求:在CORS出现前的过渡方案,利用脚本标签不受同源限制的特性。

document.domain:允许子域和父域通过设置相同domain进行通信,大型网站常有多个子域(如a.example.comb.example.com),允许同一组织控制的不同子域间安全通信,只能设置为当前域或其父域

五、CORS 解决跨域问题

5.1、对于简单请求

什么是简单请求,可以遵循以下定义:

  • 方法为 GETPOSTHEAD
  • 头部仅包含允许的字段(如 AcceptContent-Typetext/plain/multipart/form-data/application/x-www-form-urlencoded 等)
  • 无自定义头部

服务器在响应中添加 Access-Control-Allow-Origin 头,指定允许的源(或 * 表示允许任意源)

Access-Control-Allow-Origin: https://example.com

浏览器检查该头与当前源匹配后,才会允许响应数据通过。

5.2、对于非简单请求

对于非简单请求(如 PUTDELETE、自定义头部、Content-Type: application/json 等),浏览器会先发送一个 OPTIONS 方法的预检请求,询问服务器是否允许实际请求。

客户端发送的预检请求如下:

OPTIONS /api/data HTTP/1.1
Origin: https://example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type, X-Custom-Header

服务器需响应预检请求,明确声明允许的方法、头部等:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://example.com             // 允许的请求源
Access-Control-Allow-Methods: POST, GET, OPTIONS             // 允许的请求方法
Access-Control-Allow-Headers: Content-Type, X-Custom-Header  // 允许的请求头
Access-Control-Max-Age: 86400  // 缓存预检结果时间(秒)

预检通过的话,客户端就可以发送真实请求:

POST /api/data HTTP/1.1
Origin: https://example.com
Content-Type: application/json
X-Custom-Header: foo

如果预检失败,浏览器会直接拦截真实请求,并在控制台报错。

关键点:

  • 开发者无需手动处理 OPTIONS 请求,浏览器会自动完成。
  • 若预检响应头缺失或错误,真实请求会被拦截。
  • Access-Control-Max-Age 可减少重复预检请求,提升性能。

5.3、对于携带凭据的请求(Credentials)

客户端:请求时必须做额外设置

若请求需要携带 Cookie 或认证信息(如 withCredentials: true),服务器需额外声明:

Access-Control-Allow-Origin: https://example.com  // 不能为 *
Access-Control-Allow-Credentials: true

同时,客户端需显式设置 withCredentials 属性(如 Fetch API 或 Axios)。

Fetch API

fetch('https://api.example.com/data', {method: 'GET',credentials: 'include', // 必须设置为 include 才能发送凭据headers: {'Content-Type': 'application/json',},
});

XMLHttpRequest

const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data', true);
xhr.withCredentials = true; // 必须设置为 true
xhr.send();

Axios

axios.get('https://api.example.com/data', {withCredentials: true, // 必须设置为 true
});

关键点

  • credentials: 'include'(Fetch)或 withCredentials: true(XHR/Axios)必须显式设置,否则浏览器不会发送 Cookies 等凭据。
  • 即使设置了 withCredentials,服务端也必须正确响应 CORS 头,否则请求会被拦截。

服务端:响应 CORS 头(必须严格匹配)

服务端必须在响应中包含以下头部:

Access-Control-Allow-Origin: https://example.com  // 不能是 *,必须明确指定请求来源
Access-Control-Allow-Credentials: true            // 必须为 true
Access-Control-Allow-Methods: GET, POST, OPTIONS  // 允许的方法
Access-Control-Allow-Headers: Content-Type        // 允许的请求头(如自定义头)

关键限制

  • Access-Control-Allow-Origin 不能为 *
  • Access-Control-Allow-Credentials: true 必须存在
  • 如果对于非简单请求,还需要进行预检请求,和 5.1 节 5.2 节一样了

六、Gin框架中配置CORS跨域

Gin 官方推荐使用 github.com/gin-contrib/cors 中间件来配置跨域。

package mainimport ("time""github.com/gin-contrib/cors""github.com/gin-gonic/gin"
)func main() {router := gin.Default()router.Use(cors.New(cors.Config{AllowOrigins:     []string{"https://foo.com"}, // 明确允许访问的域名AllowMethods:     []string{"PUT", "PATCH"},    // 允许的http方法AllowHeaders:     []string{"Origin"},          // 允许客户端在请求中携带的头部字段ExposeHeaders:    []string{"Content-Length"},  // 允许客户端访问的额外响应头(默认只能访问简单头,如 Cache-Control、Content-Language 等)AllowCredentials: true,                        // 允许跨域请求携带凭据AllowOriginFunc: func(origin string) bool {    // 动态验证请求的 Origin 是否合法,优先级高于 AllowOrigins 字段return origin == "https://github.com"},MaxAge: 12 * time.Hour,                        // 预检请求(OPTIONS)的缓存时间}))router.Run()
}
http://www.xdnf.cn/news/8560.html

相关文章:

  • ch11 课堂参考代码 及 题目参考思路
  • Spring Cloud实战:OpenFeign远程调用与服务治理
  • Margin loss
  • C语言数据结构-单链表
  • 解锁内心的冲突:神经症冲突的理解与解决之道
  • 半导体B2B分销中台有哪些应用场景
  • 安装NBU软件及配置方法
  • 谈谈对dubbo的广播机制的理解
  • 促销活动期间,确保邮件不被标记为垃圾邮件
  • 第六十六篇 探秘Java JVM内存模型:从城市基建到程序世界的精妙映射
  • mysql8.4.3配置主从复制
  • 鸿蒙进阶——Framework之Want 隐式匹配机制概述
  • ch11题目参考思路
  • linux移植lvgl
  • 经典密码学和现代密码学的结构及其主要区别(1)维吉尼亚密码—附py代码
  • 模拟交易新维度:如何通过自营交易考试实现策略收益双提升?
  • PTA L1系列题解(C语言)(L1_105 -- L1_112)
  • OCC导入进度显示
  • Makefile快速入门
  • 直播预告 | 共探“数字化转型新引擎”,蓝卓工业互联网+AI对话夜等你来
  • 数字计数--数位dp
  • C 语言学习笔记(指针4)
  • golang 垃圾收集机制
  • 防火墙NAT地址组NAT策略安全策略
  • 50 python Matplotlib之Seaborn
  • Python爬虫实战:研究Cola框架相关技术
  • 开发工具整理
  • Python初始Flask框架
  • 敦煌网测评从环境搭建到风控应对,精细化运营打造安全测评体系
  • 【自定义类型-结构体】--结构体类型,结构体变量的创建和初始化,结构体内存对齐,结构体传参,结构体实现位段