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

跨域问题及其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.lryc.cn/news/2384792.html

相关文章:

  • 记共享元素动画导致的内存泄露
  • Flyweight(享元)设计模式 软考 享元 和 代理属于结构型设计模式
  • Win/Linux安装flash attention2
  • 【原创】ubuntu22.04下载编译AOSP 15
  • 服务器网络配置 netplan一个网口配置两个ip(双ip、辅助ip、别名IP别名)
  • 响应面法(Response Surface Methodology ,RSM)
  • 针对面试-java集合篇
  • Spring Boot 拦截器:解锁5大实用场景
  • 展锐 Android 15 锁定某个App版本的实现
  • 有两个Python脚本都在虚拟环境下运行,怎么打包成一个系统服务,按照顺序启动?
  • 【Linux cmd】查找进程信息
  • 与网格共舞 - 服务网格的运维与问题排查 (Istio 实例)
  • Python 脚本执行命令的深度探索:方法、示例与最佳实践
  • PotPlayer 4K 本地万能影音播放器
  • 2025年电工杯A题第一版本Q1-Q4详细思路求解+代码运行
  • 基于阿里云DashScope API构建智能对话指南
  • HOW - 基于组件库组件改造成自定义组件基本规范
  • 九州未来十三载:开源赋能 智启未来
  • 2025年AI搜索引擎发展洞察:技术革新与市场变革
  • dify调用Streamable HTTP MCP应用
  • HCIP实验五
  • java将图片转Base64字符串存储mysql数据库
  • 题目 3330: 蓝桥杯2025年第十六届省赛真题-01 串
  • 初识 Flask 框架
  • MYSQL故障排查和环境优化
  • vivado fpga程序固化
  • OpenCV CUDA模块图像特征检测与描述------图像中快速检测特征点类cv::cuda::FastFeatureDetector
  • SpringMVC(结合源码浅析工作流程)
  • 学习STC51单片机13(芯片为STC89C52RC)
  • Claude 4 系列 Opus 4 与 Sonnet 4正式发布:Claude 4新特性都有哪些?