同源策略及常用的跨域解决方案

636 阅读5分钟

1. 同源策略

来源:由应用协议、域名、端口号三个要素决定

同源就是来源一致。

  • 同源策略保证只有同源的应用才能访问一个应用内的信息,也就保护应用不被恶意(如XSSCSFR攻击)脚本袭击或窃取信息。
  • 在这个策略下,web浏览器允许第一个页面的脚本访问第二个页面里的数据,但是也只有在两个页面有相同的源时。这个策略可以阻止一个页面上的恶意脚本通过页面的DOM对象获得访问另一个页面上敏感信息的权限。

2. 同源策略带来的限制

同源策略使得非同源的请求受到以下限制:

  • 网络层面限制:AJAX请求不能互通
  • 数据层面限制:cookie、localstorage、indexDB不能获取异源的
  • DOM层面限制:dom不能获取和操作异源的

虽然这些限制是合理且必需的,但是有时候一些场景,需要我们能具备跨域的功能。

3. 跨域方案

3.1 利用html标签

已知有几个标签是允许跨域的:

  • img标签
  • a标签
  • link标签
  • script标签

3.1.1 JSONP

利用标签script,可以将回调函数和变量作为参数向后端发送get请求,后端拿到请求后,处理后将回调函数的调用返回给客户端,客户端接收到函数后,执行该函数。

【前端】

<html>
  <script>		
    window.myCallback = (res)=>{ //这里为上一步定义的全局函数
      console.log(res)
    }
  </script>
  <script url="xxx?callback=myCallback">
    //script标签的请求必须在写在定义全局函数之后
    //这里需将全局函数的函数名作为参数callback的value传递
    //这里callback这个键名是前后端约定好的
  </script> 
  </body>
</html>

【后端】

前端收到的拼接代码,将作为script标签内的代码,直接执行。

3.2 CORS

尽管默认情况下浏览器禁止我们访问跨域资源,但是我们可以利用 CORS 放宽这种限制,在保证安全性的前提下访问跨域资源。

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing),他允许浏览器向跨源服务器发送XMLHttpRequest请求,从而克服啦 AJAX 只能同源使用的限制。

CORS要客户端和服务端一起配合完成,其中主要是

  • 客户端发出跨域请求后,浏览器会自动向我们的 HTTP header 添加一个额外的请求头字段:Origin
  • 浏览器校验来源是否可靠,如果可靠, 服务器返回的 response 还需要加一些响应头字段,这些字段将显式表明此服务器是否允许这个跨域请求。这些字段以Access-Control-*形式,有:
    • Access-Control-Allow-Origin :必选,客户端的url是否是服务端允许的
    • Access-Control-Allow-Methods:客户端请求的方法是否是服务端所允许的
    • Access-Control-Allow-Credentials :该字段可选, 表示是否可以发送cookie
    • Access-Control-Expose-Headers :该字段可选,XHMHttpRequest对象的方法只能够拿到六种字段: Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma ,如果想拿到其他的需要使用该字段指定。
  • 浏览器拿到Response,校验Access-Control-Allow-Origin是否与origin一致来判断是否接收跨域资源

3.3 postMessage

postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:

  • 页面和其打开的新窗口的数据传递
  • 多窗口之间消息传递
  • 页面与嵌套的iframe消息传递
  • 上面三个场景的跨域数据传递

3.4 websocket

Websocket是HTML5的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。WebSocket和HTTP都是应用层协议,都基于 TCP 协议。同时,WebSocket 在建立连接时需要借助 HTTP 协议,连接建立好了之后 client 与 server 之间的双向通信就与 HTTP 无关了。

websocket本身就没有同源策略,当然由于它具有可扩展性,你也可以将它扩展成为支持同源策略的协议。

3.5 Node的中间代理(正向代理)

实现原理:同源策略是浏览器需要遵循的标准,而如果是服务器向服务器请求就无需遵循同源策略 代理服务器主要实现了转发浏览器请求转发服务器的响应

\

\

3.6 Ngnix(反向代理)

使用nginx反向代理实现跨域,是最简单的跨域方式。只需要修改nginx的配置即可解决跨域问题,支持所有浏览器,支持session,不需要修改任何代码,并且不会影响服务器性能。

ngnix实现跨域有两种方式,一种是在后端配置,一种前端本地配置。

【后端使用ngnix解决跨域】

浏览器直接访问的是代理的地址,而不是直接访问源服务器的地址。

\

【前端使用ngnix解决跨域】

比如webpack启动的本地服务,端口号是8080,也就是localhost://8080,而这个地址不能跟服务端domain.com互通(因为跨域)。可以通过ngnix配置:

  • ngnix将重新配置一个端口号为8081的,并且将这个代理到domain.com,使得localhost://8081可以和domain.com
  • 同时将8081端口号, 代理到localhost://8080这个地址,这样子8081和8080两个端口也可以互通
server {
  listen       8081;
  server_name  localhost;
  ## 用户访问 localhost,则反向代理到https://api.shanbay.com
  location / {
    proxy_pass http://domain.com;
  }
  location /api/ {
    proxy_pass http://localhost:8080;
  }
}