本文介绍: 同源策略是一种约定,它是浏览器核心也最基本安全功能,如果缺少了同源策略浏览器很容易受到XSSCSRF等攻击。所谓同源是指”协议+域名+端口“三者相同,即便两个不同的域名指向一个ip地址,也非同源。Cookie、LocalStorage、IndexedDB 等存储内容DOM 节点AJAX 请求发送后,结果浏览器拦截了。

实现跨域请求我们首先要先知道什么跨域,紧接着便是跨域方法最后则是跨域cookie处理

什么跨域

1.什么同源策略及其限制内容

同源策略是一种约定,它是浏览器核心也最基本安全功能,如果缺少了同源策略浏览器很容易受到XSSCSRF攻击。所谓同源是指”协议+域名+端口“三者相同,即便两个不同的域名指向一个ip地址,也非同源

同源策略限制内容有:

但是有三个标签是允许跨域加载资源

2.常见跨域场景

协议域名域名端口号任意一个不相同时,都算作不同域。不同域之间相互请求资源,就算作“跨域”。

特别说明两点:

跨域并不是请求发不出去,请求能发出去,服务端收到请求并正常返回结果,只是结果被浏览器拦截了。你可能会疑问明明通过表单方式可以发起跨域请求为什么 Ajax 就不会?因为归根结底,跨域是为了阻止用户读取到另一个域名下的内容,Ajax 可以获取响应,浏览器认为这不安全,所以拦截了响应。但是表单并不会获取新的内容,所以可以发起跨域请求。同时也说明了跨域并不能完全阻止 CSRF,因为请求毕竟是发出去了。

跨域有哪些方案

1.CORS

CORS 通信过程都是浏览器自动完成,需要浏览器(都支持)和服务器支持,所以关键在只要服务器支持,就可以跨域通信,CORS请求分两类,简单请求简单请求

另外CORS请求默认包含Cookie以及HTTP认证信息,如果需要包含Cookie需要满足几个条件

简单请求

需要同时满足两个条件,就属于简单请求:

需要这些条件是为了兼容表单,因为历史上表单一直可以跨域

浏览器直接发出CORS请求,具体来说就是在头信息中增加Origin字段表示请求来源来自哪个域(协议+域名+端口),服务器根据这个值决定是否同意请求。如果同意,返回的响应会多出以下响应头信息

const xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4 && xhr.status === 200) {
    console.log('收到数据:', xhr.responseText);
  }
};
xhr.open('GET', 'http://example.com/data.json', true);
xhr.send();
Access-Control-Allow-Origin: http://yourdomain.com
Access-Control-Allow-Credentials: true

在这个示例中,我们使用了 XMLHttpRequest 对象来进行跨域请求。我们设置withCredentials 属性为 true表示允许跨域请求。同时,在服务器响应中需要设置以上响应头,其中 Access-Control-Allow-Origin 表示允许哪个域名下的请求,Access-Control-Allow-Credentials 表示是否允许发送凭证(如 cookie、HTTP 认证等)。

简单请求

比如 PUT 或 DELETE 请求,或 Content-Typeapplication/json ,就是非简单请求。

简单 CORS 请求,正式请求前会发一次 OPTIONS 类型查询请求,称为预检请求,询问服务是否支持网页所在域名的请求,以及可以使用哪些头信息字段。只有收到肯定的答复,才会发起正式XMLHttpRequest请求,否则报错

预检请求的方法是OPTIONS,它的头信息中有几个字段

OPTIONS请求次数过多也会损耗性能,所以要尽量减少OPTIONS请求,可以让服务器在请求返回头部添加

Access-Control-Max-Age: Number // 数字 单位是秒

2.JSONP

JSONP 是一种常见的跨域请求方法。它是通过在 HTML 页面中添加一个 script 标签,来请求一个位于其他域名下的 JavaScript 文件。该 JavaScript 文件返回的数据需要使用一个回调函数进行包装以便在原始页面中可以接收数据

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>JSONP 示例</title>
  </head>
  <body>
    <script>
      function jsonpCallback(data) {
        console.log('收到数据:', data);
      }
      const url = 'http://example.com/data.json?callback=jsonpCallback';
      const script = document.createElement('script');
      script.src = url;
      document.body.appendChild(script);
    </script>
  </body>
</html>

在这个示例中,我们通过添加一个 script 标签来请求 http://example.com/data.json 这个地址下的数据。由于该地址存在跨域问题,我们指定了一个名为 jsonpCallback回调函数,并将回调函数名作为参数传递到了地址中。当服务器返回数据时,会自动调用回调函数并将数据作为参数传入。

3.代理

如果无法使用 JSONP 或 CORS,可以尝试使用代理服务器转发请求。在前端中,可以向自己服务器发送请求,然后服务代理请求其它域名下的资源,并将结果返回给前端。

const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4 &amp;&amp; xhr.status === 200) {
    console.log('收到数据:', xhr.responseText);
  }
};
xhr.open('GET', '/proxy?url=http://example.com/data.json', true);
xhr.send();

在这个示例中,我们向自己服务器发送了一个 GET 请求,并在请求地址中添加了一个名为 proxy参数服务接收到请求后会将该请求转发到 http://example.com/data.json 地址下,并将响应结果返回给前端。

4.WebSocket

WebSocket 是一种支持跨域请求的协议,它允许客户端服务器之间建立一个双向通信通道。通过 WebSocket 可以实现跨域传输数据。
因为WebSocket请求头信息中有Origin字段表示请求源来自哪个域,服务器可以根据这个字段判断是否允许本次通信,如果在白名单内,就可以通信
客户端代码

const socket = new WebSocket('ws://example.com/ws');
socket.onopen = function() {
  console.log('连接已建立');
  socket.send('你好,服务器!');
};
socket.onmessage = function(event) {
  console.log('收到消息:', event.data);
};
socket.onerror = function(event) {
  console.log('发生错误:', event);
};

在这个示例中,我们通过创建一个 WebSocket 对象连接 ws://example.com/ws 这个地址下的 WebSocket 服务。当连接建立成功后,我们发送了一段消息给服务器。当服务器返回消息时,会自动触发 onmessage 事件,并将服务器发送的数据作为参数传入。

需要注意的是,在使用 WebSocket 进行跨域通信时,服务器必须显式地指定允许哪些访问 WebSocket 服务。服务器需要在握手阶段返回一个 Upgrade 头部,并在该头部中指定 Origin 头部的值。以下是一个使用 Node.js 实现的 WebSocket 服务的示例代码

const WebSocketServer = require('ws').Server;
const wss = new WebSocketServer({ port: 8080 });
wss.on('connection', function(ws) {
  console.log('连接已建立');
  ws.on('message', function(message) {
    console.log('收到消息:', message);
    ws.send('你好,客户端!');
  });
});

在这个示例中,我们使用了 ws 模块创建了一个 WebSocket 服务,并监听在 8080 端口上。当客户端连接成功后,会触发 connection 事件,并返回一个 WebSocket 对象 ws。当客户端发送消息时,会自动触发 message 事件,并将客户端发送的数据作为参数传入。在这个示例中,我们将收到的消息直接返回给客户端

5.postMessage

postMessage 是一种在不同窗口或跨域框架之间进行通信的机制。它允许一个窗口向另一个窗口发送消息,无论这两个窗口是否同源。

使用 postMessage 进行通信时,需要提供目标窗口引用,并通过调用 postMessage 方法发送消息。以下是一个示例:

// 发送消息
const targetWindow = window.opener; // 获取目标窗口引用
const message = 'Hello, world!';
const targetOrigin = 'http://example.com'; // 目标窗口的源
targetWindow.postMessage(message, targetOrigin);

// 接收消息
window.addEventListener('message', function(event) {
  if (event.origin === 'http://example.com') {
    const message = event.data;
    console.log('收到消息:', message);
    // 处理接收到的消息
  }
});

在这个示例中,首先获取了目标窗口引用 targetWindow然后通过调用 postMessage 方法向目标窗口发送消息。发送的消息可以是任意类型的数据,例如字符串对象等。

接收消息的窗口中,通过添加 message 事件监听器来监听消息的接收然后通过 event.data 获取收到的消息内容。可以通过 event.origin验证消息来源的域,确保只接受来自指定域的消息。

需要注意的是,为了确保安全性应该始终在 postMessage 中指定目标窗口的源,以防止恶意窗口的干扰。同时,在接收消息时,应该对消息来源进行验证,并仅处理来自可信任源的消息。

总结来说,postMessage 提供了一种安全的跨窗口通信机制,可以在不同窗口、跨域框架之间进行双向通信

这里只介绍几种开发中用的比较多的,几乎用不到的比如:

跨域时 Cookie 要做何处理

在跨域请求中,Cookie处理需要额外注意。默认情况下,跨域请求是不会携带 Cookie 的,这是出于安全考虑

如果你想在跨域请求中携带 Cookie,有以下几种方法:

  1. CORS(跨域资源共享:在服务端设置响应头部,允许指定的源携带 Cookie。具体做法是,在服务器返回的响应头中添加 Access-Control-Allow-Credentials: true表示允许携带凭证(如 Cookie);同时,需要指定允许访问的源,可以使用 Access-Control-Allow-Origin: http://yourdomain.com限制只允许特定域名的请求携带 Cookie。

  2. 代理:将跨域请求发送到自己的服务器上,然后再由自己的服务器转发请求,并将响应返回给前端。由于请求是在同源下发起的,因此可以携带 Cookie。前端将请求发送给自己的服务器,然后自己的服务器再将请求发送给目标服务器,并将目标服务器的响应返回给前端。

  3. 在 URL 中传递参数:可以将需要的信息以参数的形式附加在 URL 上,而不是通过 Cookie 传递。这样不会触发同源策略,也不会引起跨域问题。

需要注意的是,使用 Cookie 进行跨域请求时,还需要设置 XMLHttpRequest 对象的 withCredentials 属性为 true。例如

const xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.open('GET', 'http://example.com/api', true);
xhr.send();

同时,在服务端也要对跨域请求进行相应的处理,以确保安全性

原文地址:https://blog.csdn.net/He_9a9/article/details/134703732

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_20516.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注