# 一、同源策略

同源策略是浏览器最核心的安全功能,没有同源策略,网页很容易受到xss,csrf攻击。同源指的是同域名、同端口、同协议。三者必须同时满足,即使是两个不同域名执行同一个ip地址,也是非同源。

# 1.同源限制什么内容?

  • Cookie、LocalStorage、IndexedDB 等存储性内容
  • DOM 节点
  • AJAX 请求发送后,结果被浏览器拦截了

哪些标签可以跨域:img/link/script

# 二、跨域解决方案

# 1.jsonp

# jsonp原理

利用script标签没有跨域限制的漏洞,网页可以得到其他来源动态产生的json的数据,jsonp请求需要对方服务器做支持才可以

# JSONP和AJAX对比

相同:都是从客户端向服务器发送请求,从服务端获取数据

不同:AJAX属于同源策略,JSONP属于非同源策略

# JSONP优缺点

优点:简单,兼容性好,解决主流浏览器跨域数据访问

缺点:只有get方法,也有遭受xss攻击的可能性

# 2.CORS

CORS 需要浏览器和后端同时支持。IE 8 和 9 需要通过 XDomainRequest 来实现

浏览器自动进行cors跨域,实现cors通信关键在于后端。 服务端设置 Access-Control-Allow-Origin 就可以开启 CORS。 该属性表示那些域名可以访问资源,设置通配符代表所有网站都可以访问。有两种情况,简单请求和复杂请求。

# 简单请求

同时满足以下两个条件,就是简单请求

条件2:使用下列方法之一

  • GET
  • HEAD
  • POST

条件2:Content-Type 的值仅限于下列三者之一:

  • text/plain
  • multipart/form-data
  • application/x-www-form-urlencoded

# 复杂请求

不符合以上条件的请求就肯定是复杂请求了。 复杂请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求,该请求是 option 方法的,通过该请求来知道服务端是否允许跨域请求。

我们用PUT向后台请求时,属于复杂请求,后台需做如下配置:

// 允许哪个方法访问我
res.setHeader('Access-Control-Allow-Methods', 'PUT')
// 预检的存活时间
res.setHeader('Access-Control-Max-Age', 6)
// OPTIONS请求不做任何处理
if (req.method === 'OPTIONS') {
  res.end() 
}
// 定义后台返回的内容
app.put('/getData', function(req, res) {
  console.log(req.headers)
  res.end('我不爱你')
})

# 3.postMessage

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

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

postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递

otherWindow.postMessage(message, targetOrigin, [transfer]);

  • message: 将要发送到其他 window的数据。
  • targetOrigin:通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示无限制)或者一个URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。
  • transfer(可选):是一串和message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。

接下来我们看个例子: http://localhost:3000/a.html页面向http://localhost:4000/b.html传递“我爱你”,然后后者传回"我不爱你"。

// a.html
  <iframe src="http://localhost:4000/b.html" frameborder="0" id="frame" onload="load()"></iframe> //等它加载完触发一个事件
  //内嵌在http://localhost:3000/a.html
    <script>
      function load() {
        let frame = document.getElementById('frame')
        frame.contentWindow.postMessage('我爱你', 'http://localhost:4000') //发送数据
        window.onmessage = function(e) { //接受返回数据
          console.log(e.data) //我不爱你
        }
      }
    </script>
复制代码
// b.html
  window.onmessage = function(e) {
    console.log(e.data) //我爱你
    e.source.postMessage('我不爱你', e.origin)
 }

# 4.nginx

// proxy服务器
server {
    listen       81;
    server_name  www.domain1.com;
    location / {
        proxy_pass   http://www.domain2.com:8080;  #反向代理
        proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
        index  index.html index.htm;

        # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
        add_header Access-Control-Allow-Origin http://www.domain1.com;  #当前端只跨域不带cookie时,可为*
        add_header Access-Control-Allow-Credentials true;
    }
}
最后更新于: 12/25/2020, 9:20:27 AM