同源策略与解决方法

news2024/11/17 7:21:50

同源策略与解决方法

1.浏览器的同源策略

1.1 同源策略

同源策略(same origin policy),一种安全策略,用于限制一个源的文档或者它加载的脚本如何能与另一个源的资源进行交互。

浏览器默认两个不同的源之间是可以互相访问资源和操作 DOM 的。两个不同的源之间若是想要访问资源或者操作 DOM,就会受到同源策略的制约。

1.2 同源

同源:URL 的协议、主机、端口号相同。

解释一下协议、主机、端口号:

  • 协议:协议是定义了数据如何在计算机内和之间进行交换的规则的系统,例如 HTTP、HTTPS。
  • 主机:是已连接到一个计算机网络的一台电子计算机或其他设备。网络主机可以向网络上的用户或其他节点提供信息资源、服务和应用。使用 TCP/IP 协议族参与网络的计算机也可称为 IP 主机。
  • 端口:主机是计算机到计算机之间的通信,那么端口就是进程到进程之间的通信。

1.3 限制

同源策略的限制:

  • DOM 访问限制:DOM 和 Js 对象无法获得。同源策略限制了网页脚本(如 JavaScript)访问其他源的 DOM。这意味着通过脚本无法直接访问跨源页面的 DOM 元素、属性或方法。(防止恶意网站从其他网站窃取敏感信息)
  • Web 数据限制:Cookie、LocalStorage 和 IndexDB 无法读写。限制从其他源加载的 Web 数据(例如 XMLHttpRequest 或 Fetch API)。在同源策略下,XMLHttpRequest 或 Fetch 请求只能发送到与当前网页具有相同源的目标。(这有助于防止跨站点请求伪造(CSRF)等攻击)
  • 网络通信限制:AJAX 请求不能发送,浏览器会阻止从一个源发出的请求获取来自其他源的响应。这样做是为了确保只有受信任的源能够与服务器进行通信,以避免恶意行为。

2. 跨域解决方案

2.1 ajax 跨域请求方案 jsonp

jsonp(JSON with Padding),是 JSON 的一种 “使用模式”,可以让网页跨域读取数据,其本质是利用 script 标签的开放策略,浏览器传递 callback 参数到后端,后端返回数据时会将 callback 参数作为函数名来包裹数据,从而浏览器就可以跨域请求数据并制定函数来自动处理返回数据。

在这里插入图片描述

demo:

var script = document.createElement('script');
script.type = 'text/javascript';
// 传参callback给后端,后端返回时执行这个在前端定义的回调函数
script.src = 'http://a.qq.com/index.php?callback=handleCallback';
document.head.appendChild(script);
// 回调执行函数
function handleCallback(res) {
  alert(JSON.stringify(res));
}

优点:

  • jsonp 兼容性强,适用于所有浏览器,尤其是 IE10 以下浏览器

缺点:

  • 没有关于调用错误的处理
  • 只支持 GET 请求,不支持 POST 以及大数据量的请求,也无法拿到相关的返回头,状态码等数据
  • callback 参数恶意注入,可能会造成 xss 漏洞
  • 无法设置资源访问权限

2.2 跨域资源共享(CORS)

浏览器限制

情景:跨站请求正常发送,但是结果被浏览器拦截。

原因:浏览器将不同域的内容隔离在不同的进程中,网络进程负责下载资源并将其送到渲染进程中,但由于跨域限制,某些资源可能被阻止加载到渲染进程。如果浏览器发现一个跨域响应包含了敏感数据,它可能会阻止脚本访问这些数据,即使网络进程已经获得了这些数据。CORB 的目标是在渲染之前尽早阻止恶意代码获取跨域数据。

CORS

跨源资源共享(Cross-Origin Resource Sharing,CORS)是一种允许在受控的条件下,不同源的网页能够请求和共享资源的机制。

CORS 整个通信过程都是浏览器自动完成,浏览器一旦发现 ajax 请求跨源,就会自动在头信息中增加 Origin 字段,用来说明本次请求来自哪个源(协议+域名+端口)。因此,实现 CORS 通信的关键是服务器,需要服务器配置 Access-Control-Allow-Origin 头信息。
基本思想:

  • 服务器在响应中提供一个标头(HTTP 头),指示哪些源被允许访问资源。
  • 浏览器在发起跨域请求时会先发送一个预检请求(OPTIONS 请求)到服务器,服务器通过设置适当的 CORS 标头来指定是否允许跨域请求,并指定允许的请求源、方法、标头等信息。

CORS 的请求根据是否会触发 OPTIONS 请求,分为两类:

  • 简单请求:不触发 CORS 的请求
  • 预检请求:在正式通信之前,增加一次 OPTIONS 查询请求。

简单请求

需要满足的条件:

  • HTTP 方法限制:只能使用 GET、HEAD、POST 这三种 HTTP 方法之一。如果请求使用了其他 HTTP 方法,就不再被视为简单请求。
  • 自定义标头限制:请求的 HTTP 标头只能是以下几种常见的标头:Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type(仅限于 application/x-www-form-urlencoded、multipart/form-data、text/plain)。HTML 头部 header field 字段:DPR、Download、Save-Data、Viewport-Width、WIdth。如果请求使用了其他标头,同样不再被视为简单请求。
  • 请求中没有使用 ReadableStream 对象。
  • 不使用自定义请求标头:请求不能包含用户自定义的标头。
  • 请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器;XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问

预检请求

  • 预检请求:在正式通信之前,增加一次 OPTIONS 查询请求。服务器通过了 预检请求,以后每次浏览器正常的 CORS 请求,就都跟简单请求一样,会有一个 Origin 头信息字段。服务器的回应,也都会有一个 Access-Control-Allow-Origin 头信息字段。

第一个类型为 preflight 就是预检请求:

在这里插入图片描述

查看预检请求的请求头数据:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

OPTIONS 请求头中的特殊字段:

  • ccess-Control-Request-Method:该字段是必须的,用来列出浏览器的 CORS 请求会用到哪些 HTTP 方法。
  • Access-Control-Request-Headers:该字段是一个逗号分隔的字符串,指定浏览器 CORS 请求会额外发送的头信息字段。即告知服务器,实际请求将携带的自定义请求首部字段。

查看预检请求的响应头数据:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

OPTIONS 响应头中的特殊字段:

  • Access-Control-Allow-Credentials(可选):值是一个布尔值,表示是否允许发送 Cookie。默认情况下,Cookie 不包括在 CORS 请求之中。设为 true,即表示服务器明确许可,前端也需要设置 withCredentials,Cookie 可以包含在请求中,一起发给服务器。这个值也只能设为 true,如果服务器不要浏览器发送 Cookie,删除该字段即可。
  • Access-Control-Expose-Headers(可选):CORS 请求时,XMLHttpRequest 对象的 getResponseHeader()方法只能拿到 6 个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在 Access-Control-Expose-Headers 里面指定。
  • Access-Control-Allow-Methods:表明服务器允许客户端使用什么方法发起请求
  • Access-Control-Allow-Origin:(必须):表示可以请求的数据,可以设置为* 符号,表示允许任意跨源请求。
  • Access-Control-Allow-Headers:将实际请求所携带的首部字段告诉服务器

OPTIONS 请求的更多信息,可参考官方文档

在这里插入图片描述

优点与缺点

优点:

  • 支持所有类型的 HTTP 请求,功能完善。
  • 通过 onerror 事件监听进行调用错误处理;
  • 通过 Access-Control-Allow-Origin 进行资源访问授权。

缺点:

  • 目前主流浏览器(IE10 及以上)都支持 CORS,但 IE8 和 IE9 需要使用 XDomainRequest 对象进行兼容,IE7 及以下浏览器不支持。

2.3 服务器代理

后端进行代理中转请求至服务器端,然后将获取的数据返回给前端。

外网前端页面无法访问内网接口,配置代理接口允许前端页面访问,并中转内网接口,则外网前端页面可以跨域访问内网接口。

比如配置 Nginx,将接收到的请求转发到内网:

    server{
        #如果是静态文件,直接指向目录
        location / {
            root   html;
            index  index.html index.htm;
        }
        # 如果是动态应用,用proxy_pass转发一下
        location ~ ^/api/(.*?)$ {
             proxy_pass  http://127.0.0.1:8080/api/$1?$args;
        }
    }

优点:

  • 前端无需进行任何改变

缺点:

  • 后端需要一定工作量

2.4 前端跨域

前端跨域通信是指浏览器中两个不符合同源策略的前端页面进行通信。

2.4.1 document.domain+iframe

仅适用于主域相同,子域不同的前端通信跨域场景。

核心点:

  • A 嵌套 B
  • 将 document.domain 指向主域名

页面 A:

<!-- A页面 http://a.qq.com/a.html -->
<iframe id="iframe" src="http://b.qq.com/b.html"></iframe>
<script>
  document.domain = 'qq.com';
  var windowB = document.getElementById('iframe').contentWindow;
  alert('B页面的user变量:' + windowB.user);
</script>

页面 B:

<!-- B页面 http://b.qq.com/b.html -->
<script>
  document.domain = 'qq.com';
  var user = 'saramliu';
</script>

2.4.2 location.hash+iframe

利用 url 的 hash 值改变但不刷新页面的特性,实现简单的前端跨域通信。

受到浏览器安全机制的限制,A 嵌套 B,A 可以修改 B 的 hash 值,但 B 不能修改 A 的 Hash 值,需要一个与 A 同源的页面来中转。

A 页面:

<!-- A页面 http://a.qq.com/a.html -->
<iframe id="iframe" src="http://b.qq1.com/b.html"></iframe>
<script>
  // 监听c.html传来的hash值
  window.onhashchange = function () {
    alert('B页面传递数据:' + location.hash.substring(1));
  };
</script>

B 页面:

<!-- B页面 http://b.qq1.com/b.html -->
<iframe id="iframe" src="http://a.qq.com/c.html"></iframe>
<script>
  // 向c.html传递hash值
  var iframe = document.getElementById('iframe');
  setTimeout(function () {
    iframe.src = iframe.src + '#user=saramliu';
  }, 1000);
</script>

中转页面:

<!-- C页面 http://a.qq.com/c.html -->
<script>
  // 监听b.html传来的hash值
  window.onhashchange = function () {
    // 操作同域a.html的hash值,传递数据
    window.parent.parent.location.hash = window.location.hash.substring(1);
  };
</script>

优点:

  • 可以解决主域不同的前端通信跨域问题。
  • hash 改变,页面不会刷新。

缺点:

  • 受部分浏览器安全机制限制,需要额外的同源中转页面,且中转页面需要 js 逻辑来修改 hash 值。
  • 通信数据类型及长度均受限,且数据外显在 url 上,存在一定安全风险。

2.4.3 window.name+iframe

window.name 属性在不同页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。

A 嵌套 B,B 将要传递的数据附加到 window.name 上,然后跳转到与 A 同域名的 C,A 和 C 满足同源策略,A 可与获取到 C 的 window.name。

A

<!-- A页面 http://a.qq.com/a.html -->
<iframe id="iframe" src="http://b.qq1.com/b.html"></iframe>
<script>
  var state = 0;
  var iframe = document.getElementById('iframe');
  iframe.onload = function () {
    if (state === 1) {
      // 第2次onload成功后,读取同域window.name中数据
      alert(iframe.contentWindow.name);
    } else if (state === 0) {
      // 第1次onload成功后
      state = 1;
    }
  };
</script>

B:

<!-- B页面 http://b.qq1.com/b.html -->
<script>
  window.name = '这里是B页面!';
  window.location = 'http://a.qq.com/c.html'; // 跳转到与A同源的C
</script>

优点:

  • 通信数据类型不受限,且长度可达 2MB。

缺点:

  • 需要额外的同源中转页面,但中转页可以为空白页。

2.4.4 postMessage

postMessage 是 HTML5 XMLHttpRequest Level2 中的 API,是一种安全的跨域通信方法,且是为数不多可以跨域操作的 window 属性之一,它通常用于解决以下方面的问题:

  • 页面和其打开的新窗口的数据传递。
  • 多窗口之间消息传递。
  • 页面与嵌套 iframe 消息传递。

A 获得 B 的 window 对象后,A 调用 postMessage 方法发送一个个 MessageEvent 消息。B 通过监听 message 事件即可获取 A 传递的数据。

A:

<iframe id="iframe" src="http://b.qq1.com/b.html"></iframe>
<script>
  var iframe = document.getElementById('iframe');
  iframe.onload = function () {
    var data = { meesage: '这里是A页面发的消息' };
    var url = 'http://b.qq1.com/b.html'; // 向B页面发送消息
    iframe.contentWindow.postMessage(JSON.stringify(data), url);
  };
  window.addEventListener('message', function (e) {
    alert('B页面发来消息:' + JSON.parse(e.data));
  });
</script>

B:

<!-- B页面 http://b.qq1.com/b.html -->
<script>
  window.addEventListener(
    'message',
    function (e) {
      alert('A页面发来消息:' + JSON.parse(e.data));
      var data = { meesage: '这里是B页面发的消息' };
      var url = 'http://a.qq.com/a.html';
      window.parent.postMessage(JSON.stringify(data), url);
    },
    false
  );
</script>

优点:

  • 可以解决多种类型的前端跨域通信问题。

缺点:

  • 兼容性方面相对差一点,IE8 及以下浏览器不支持该方法,IE9 只支持 postMessage 传递 string 类型的数据,而标准的 postMessage 消息数据可以是任何类型。

参考文档

  • 同源策略(same origin policy)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/947137.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

reactantd(12)动态表单的默认值问题

最近遇到一个需求是有一个表单可以输入各种信息&#xff0c;然后还需要有一个编辑功能&#xff0c;点击编辑的时候需要把当前数据填入到表单里面。在网上查了很多种方法&#xff0c;然后我的思路是使用initialValues搭配setState()使用。默认值都为空&#xff0c;然后点击单条数…

Microsoft Edge 主页启动diy以及常用的扩展、收藏夹的网站

一、Microsoft Edge 主页启动diy 二、常用的扩展 1、去广告&#xff1a;uBlock Origin 2、翻译&#xff1a; 页面翻译&#xff1a;右键就有了&#xff0c;已经内置了划词翻译 3、超级复制 三、收藏夹的网站

函数(个人学习笔记黑马学习)

1、函数定义 #include <iostream> using namespace std;int add(int num1, int num2) {int sum num1 num2;return sum; }int main() {system("pause");return 0; } 2、函数的调用 #include <iostream> using namespace std;int add(int num1, int num2…

java内存模型讨论及案例分析

常用内存选项 -Xmx&#xff1a; 最大堆大小 -Xms&#xff1a;最小堆大小 -Xss &#xff1a;线程堆栈大小&#xff0c;默认1M 生产环境最好保持 Xms Xmx java内存研究 内存布局 可见&#xff1a; 堆大小 新生代 老年代&#xff0c;新生代EFrom SurvivorTo Survivor。新…

【数学建模竞赛】各类题型及解题方案

评价类赛题建模流程及总结 建模步骤 建立评价指标->评价体系->同向化处理&#xff08;都越多越好或越少越少&#xff09;->指标无量纲处理 ->权重-> 主客观->合成 主客观评价问题的区别 主客观概念主要是在指标定权时来划分的。主观评价与客观评价的区别…

Vulnhub内网渗透DC-6靶场通关

个人博客 xzajyjs.cn IP DC-6: 192.168.168.4 Kali: 192.168.168.5 信息搜集 arp-scan -l # nmap -sn 192.168.168.0/24进行主机发现&#xff0c;探测到靶机IP。 使用nmap进行端口扫描 nmap -sV -A 192.168.168.4开放了一个ssh和http端口&#xff0c;80端口是wordpress5.1…

MinIO框架安装使用+实现上传需求

MinIO框架 什么是MinIO框架如何安装&#xff08;Docker版&#xff09;安装步骤1. 查询MinIO的服务版本2. 拉取MinIO3.启动报错在docker中没有操作文件的权限 4. 访问 简单配置1.找到创建用户界面2. 设置用户信息3. 创建一个桶 使用MinIO依赖搭建MinIO的初始化API存储桶的基本操…

uniapp 开发小程序,封装一个方法,让图片使用线上地址

1.在main.js文件中&#xff0c;添加以下代码&#xff1a; 复制使用&#xff1a; // 图片使用网络地址 Vue.prototype.localImgSrc function(img){//项目的地址域名&#xff0c;例如百度return "https://baidu.cn/static/index/images/" img; }2.在页面中直接使用&…

PMP是什么?项目管理证书好考吗?

PMP是由项目管理协会&#xff08;Project Management Institute&#xff0c;简称PMI&#xff09;发起的项目管理专业人士资格认证&#xff0c;严格评估项目管理人员知识技能是否具有高品质的资格认证考试。PMP证书究竟难不难考呢&#xff1f;接下来的文章将简要讨论PMP证书的考…

git 基础

1.下载安装Git&#xff08;略&#xff09; 2.打开git bash窗口 3.查看版本号、设置用户名和邮箱 用户名和邮箱可以随意起&#xff0c;与GitHub的账号邮箱没有关系 4.初始化git 在D盘中新建gitspace文件夹&#xff0c;并在该目录下打开git bash窗口 git init 初始化完成后会…

【微服务部署】06-日志集成

文章目录 1. EFK日志三件套集成1.1 核心组件1.2 部署 2. Exceptionless日志系统2.1 Exceptionless核心特性2.2 Exceptionless部署文件2.3 K8s中使用Exceptionless 1. EFK日志三件套集成 1.1 核心组件 Elasticsearch&#xff08;存储&#xff09;Fluentd&#xff08;收集器&am…

文件上传漏洞-upload靶场3-4(全网最详细解读)

文件上传漏洞-upload靶场3-4关通关笔记&#xff08;全网最详细解读&#xff09; upload 第三关&#xff08;特殊后缀&#xff09; 思路 按照第一关和第二关的思路&#xff0c;先随便上传一个文件用burpsuite工具抓包&#xff0c;看它到底是前段验证还是后端验证。 上传一个we…

ADB安装及命令-自用查询

常用ADB命令整理 ADB简介常用命令整理查看设备及安装卸载屏幕事件⽇志查询查询系统服务情况其它 adb 命令 ADB安装ADB连接设备Android 实体机连接准备Android 虚拟机连接准备 ADB简介 ADB&#xff0c;即 安卓调试桥 (Android Debug Bridge, adb)&#xff0c;它是 Android 开发…

分布式系统的多数据库,实现分布式事务回滚(1.7.0 seata整合2.0.4nacos)

正文 1、解决的应用场景是分布式事务&#xff0c;每个服务有独立的数据库。 2、例如&#xff1a;A服务的数据库是A1&#xff0c;B服务的数据库是B2&#xff0c;A服务通过feign接口调用B服务&#xff0c;B涉及提交数据到B2&#xff0c;业务是在B提交数据之后&#xff0c;在A服…

数学建模:层次分析法

&#x1f506; 文章首发于我的个人博客&#xff1a;欢迎大佬们来逛逛 层次分析法 步骤描述 将问题条理化&#xff0c;层次化&#xff0c;构建出一个有层次的结构模型。层次分为三类&#xff1a;目标层&#xff0c;准则&#xff08;指标&#xff09;层&#xff0c;方案层。比…

Mybatis1.6 添加数据

1.6 添加数据 1.6.1 编写接口方法1.6.2 编写SQL语句1.6.3 编写测试方法1.6.4 添加-主键返回 如上图是我们平时在添加数据时展示的页面&#xff0c;而我们在该页面输入想要的数据后添加 提交 按钮&#xff0c;就会将这些数据添加到数据库中。接下来我们就来实现添加数据的操作。…

前端调用电脑摄像头

项目中需要前端调用&#xff0c;所以做了如下操作 先看一下效果吧 主要是基于vue3&#xff0c;通过canvas把画面转成base64的形式&#xff0c;然后是把base64转成 file文件&#xff0c;最后调用了一下上传接口 以下是代码 进入页面先调用一下摄像头 navigator.mediaDevices.ge…

低成本32位单片机电动工具无感方波控制方案

RAMSUN介绍基于灵动32位微处理器MM32SPIN0230的BLDC电动工具无感方波控制方案&#xff0c;包括MM32SPIN0230芯片资源。 以下是电动工具无感方波控制方案的简述&#xff1a; MM32SPIN0230电动工具专用板 芯片介绍 MM32SPIN0230系列是灵动微MindSPIN旗下高性能的单电机控制产品…

04-基础例程4

基础例程4 1、RGB彩灯 实验介绍 ​ WS2812B是一款智能控制的LED光源&#xff0c;控制电路和RGB芯片集成在一个5050组件的封装中。 ​ 可以将多个RGB灯珠级联&#xff0c;如下图所示&#xff1a; ​ 3个最基本的颜色为红、绿、蓝&#xff08;RGB&#xff09;&#xff0c;均是…

Elasticsearch实战(三):Springboot实现Elasticsearch搜索推荐

文章目录 系列文章索引一、什么是搜索推荐二、新增测试数据三、搜索推荐的实现1、es官网2、Java实现搜索推荐3、总结 系列文章索引 Elasticsearch实战&#xff08;一&#xff09;&#xff1a;Springboot实现Elasticsearch统一检索功能 Elasticsearch实战&#xff08;二&#x…