zoukankan      html  css  js  c++  java
  • 浏览器-同源政策(same-origin policy)

    浏览器安全的基石是“同源政策”(same-origin policy)。

    1995年,同源政策由 Netscape 公司引入浏览器。目前,所有浏览器都实行这个政策。

    何为同源?

    • 协议相同
    • 域名相同
    • 端口相同

    限制范围

    • Cookie、LocalStorage 和 IndexedDB 无法读取。
    • DOM 无法获得。
    • AJAX 请求不能发送。

      PS:Form表单提交不受同源政策限制;

    一级域名相同,二级域名不同网页Cookie 和 iframe规避同源政策

    一级域名相同,只是二级域名不相同的2个网页(A页和B页)间通信(共享cookie和ifrmame DOM):

    //A网页通过脚本设置一个 Cookie
    document.cookie = "test1=hello";
    
    //B网页不能读取
    var allCookie = document.cookie;
    
    //父窗口不能读取子iframe的DOM对象,报错
    document.getElementById("myIFrame").contentWindow.document
    
    //同样子窗口不能获取父窗口的元素,报错
    window.parent.document.body

    如果两个窗口一级域名相同,只是二级域名不同,那么设置document.domain属性,就可以规避同源政策,共享cookie和获取DOM,解决上面的问题:

    //设置为一级域名,规避同源政策
    document.domain = 'example.com';

    完全不同源网站解决跨域窗口间通信问题

    有2种方法:

    • 片段识别符(fragment identifier)
    • 跨文档通信API(Cross-document messaging)

    片段识别符(fragment identifier),指的是URL的#号后面的部分,将此作为两个窗口通信内容的中介存储,可互为读取,实现通信。

    父窗口把信息写入子窗口的片段识别符:

    var src = originURL + '#' + data;
    document.getElementById('myIFrame').src = src;

    子窗口通过监听hashchange事件,得到通知:

    window.onhashchange = checkMessage;
    
    function checkMessage() {
      var message = window.location.hash;
      // ...
    }

     同样,子窗口也可以改变父窗口的片段识别符:

    parent.location.href= target + “#” + hash;

    上面两种方法都属于破解,HTML5为了解决这个问题,引入了一个全新的API:跨文档通信 API(Cross-document messaging)。

    这个API为window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源:

     父窗口向子窗口发送消息:

    var popup = window.open('http://bbb.com', 'title');
    popup.postMessage('Hello World!', 'http://bbb.com');

    子窗口向父窗口发送消息:

    window.opener.postMessage('Nice to see you', 'http://aaa.com');

    postMessage方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(origin),即“协议 + 域名 + 端口”。也可以设为*,表示不限制域名,向所有窗口发送。

    父窗口或子窗口监听对方发来的消息:

    window.addEventListener('message', function(e) {
      console.log(e.data);
    },false);

    message事件的事件对象提供3个属性:

    • event.source:发送消息的窗口
    • event.origin: 消息发向的网址
    • event.data: 消息内容

    子窗口通过event.source属性引用父窗口,然后回复消息:

    window.addEventListener('message', receiveMessage);
    function receiveMessage(event) {
      event.source.postMessage('Nice to see you!', '*');
    }

    event.origin属性可以过滤不是发给本窗口的消息:

    window.addEventListener('message', receiveMessage);
    function receiveMessage(event) {
      if (event.origin !== 'http://aaa.com') return;
      if (event.data === 'Hello World') {
          event.source.postMessage('Hello', event.origin);
      } else {
        console.log(event.data);
      }
    }

    一个跨文档通信API案例:

    //父窗口发送消息的代码
    var win = document.getElementsByTagName('iframe')[0].contentWindow;
    var obj = { name: 'Jack' };
    win.postMessage(JSON.stringify({key: 'storage', data: obj}), 'http://bbb.com');
    
    //子窗口接收消息,写入localStorage
    window.onmessage = function(e) {
      if (e.origin !== 'http://bbb.com') {
        return;
      }
      var payload = JSON.parse(e.data);
      localStorage.setItem(payload.key, JSON.stringify(payload.data));
    };

    AJAX与同源政策

    同源政策规定,AJAX请求只能发给同源的网址,否则就报错。

    AJAX有3种方法规避同源政策:

    • JSONP
    • WebSocket
    • CORS

    第1种:JSONP

    JSONP是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,老式浏览器全部支持,服务器改造非常小。

    它的基本思想是,网页通过添加一个<script>元素,向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据以一个指定名字的回调函数的参数形式传回客户端,客户端在约定名字的回调函数中处理接收到的参数 。

    首先,网页动态插入<script>元素,由它向跨源网址发出请求。

    function addScriptTag(src) {
      var script = document.createElement('script');
      script.setAttribute("type","text/javascript");
      script.src = src;
      document.body.appendChild(script);
    }
    
    window.onload = function () {
      addScriptTag('http://example.com/ip?callback=foo');
    }
    
    function foo(data) {
      console.log('Your public IP address is: ' + data.ip);
    };

    服务器收到这个请求以后,会将数据放在回调函数的参数位置返回:

    foo({
      "ip": "8.8.8.8"
    });

    由于<script>元素请求的脚本,直接作为代码运行。这时,只要浏览器定义了foo函数,该函数就会立即调用。作为参数的JSON数据被视为JavaScript对象,而不是字符串,所以不用JSON.parse处理,直接作为JSON对象使用。

    参考

    同源政策,阮一峰 http://javascript.ruanyifeng.com/bom/same-origin.html 

  • 相关阅读:
    Flask 中的路由系统
    Flask 中内置的 Session
    Flask中的模板语言jinja2
    Flask 中的 5种返回值
    Redis快速入门
    动态实现前后台分页、翻页按钮、上一页、下一页、首页、末页
    bus.js非父子组件之间通讯
    vue中父子组件之间相互传值
    js实现加减乘除
    禁用微信分享
  • 原文地址:https://www.cnblogs.com/ybtools/p/6733642.html
Copyright © 2011-2022 走看看