同源策略和跨域实现

同源策略和跨域实现

同源策略
  1. 怎样才算同源

    同源是指域名(主机名或者ip地址)、端口、协议相同。不同的客户端脚本(javascript、ActionScript)在没有明确授权的情况下,不允许读取对方的资源。

    下面举例,与URL”http://www.example.com/dir/page.html“进行对比说明:(转自http://www.jianshu.com/p/beb059c43a8b

对比URL结果分析
http://www.example.com/dir/page2.html同源协议相同、主机相同、端口相同
http://www.example.com/dir2/other.html同源协议相同,主机相同、端口相同
http://username:password@www.example.com/dir2/other.html同源协议相同、主机相同、端口相同
http://www.example.com:81/dir/other.html不同源协议相同,主机相同,端口不同
https://www.example.com/dir/other.html不同源协议不同
http://en.example.com/dir/other.html不同源主机不同
http://example.com/dir/other.html不同源主机不同(需要精确匹配)
http://v2.www.example.com/dir/other.html不同源主机不同
http://www.example.com:80/dir/other.html看情况端口明确,依赖浏览器实现



2. 什么是同源策略
同domain( 或者ip),同端口,同协议视为同一个域,一个域内的脚本仅仅具有本域内的权限,可以理解为本域脚本只能读写本域内的资源,而无法访问其他域的资源,这种安全限制称为同源策略。同源策略是由Netscape提出的一个安全策略.

3. 同源策略的优缺点
同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少同源策略,浏览器很容易受到XSS、CSFR等攻击。这是同源策略的优点,它提升了web前段的安全性,它为安全上网等提供了一定的保障。但同时,也在一定程度上限制了web拓展上的灵活性。

跨域实现
  1. 什么是跨域

    因为同源策略的限制,浏览器不能执行其他网站的脚本,但有时候,我们需要访问其他网站的脚本,这时候就需要实现跨域访问。跨域是指从一个域名的网页去请求另一个域名的资源,实现在不同的域之间进行数据传输或通信。主要协议,域名,端口有任何一处不同则被视为跨域。

解决跨域问题的几种方法

参考链接:http://blog.csdn.net/joyhen/article/details/21631833
参考链接:
http://www.cnblogs.com/2050/p/3191744.html#commentform

参考链接:http://web.jobbole.com/88519/

参考链接:http://web.jobbole.com/88530/

参考链接:
http://blog.csdn.net/kongjiea/article/details/44201021(分了单向跨域和双向跨域)

需要注意:

  • 协议和端口造成的跨域问题,“前台”是 无能为力的

  • 在跨域问题上,域仅仅是通过“URL”的首部来识别而不会是识别相同的ip地址对应着两个域,或者两个不同的ip地对应着同一个域。

    1. 通过jsonp跨域

      • 什么是jsonp

      jsonp简单地可以理解为json的一种”使用模式“,是应用json的一种方法。jsonp由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数,而数据就是传入回调函数中的json数据。

      • 实现

      在js中,我们直接用XMLHttpRequest请求不同域上的数据是不可以的,而在html中,能够实现跨域的几种方式就是:

      link属性(css)、href属性(a标签)、src(img标签、script标签)

      即在页面上引入不同域的js脚本文件却是可以的,jsonp正好利用了这一特性。

      假如a.html页面中,需要利用ajax获取不同域上的json数据,json数据所在地址为http://example.com/data.php ,a.html页面中的代码实现如下:

      <script>
      function dosomething(jsondata){
         //处理获取的json数据
      }
      </script>
      <script src="http://example.com/data.php?callback=dosomething"></script>

      js文件载入成功后会执行我们在url参数中指定的函数,并且会把我们需要的json数据作为参数。所以jsonp是需要服务器端的页面进行相应的配合。以php实现为例

      <?php
      $callback = $_GET['callback']; //得到回调函数名
      $data=arry('a','b','c'); //要返回的数据
      echo $callback.'('.json_encode($data).')';//输出

      所以,最终的输出结果是 dosomething([‘a’ , ‘b’ , ‘c’]).

      如果使用jquery,在html页面中可以使用下面的代码

      <script>
      $.getJSON('http://example.com/data.php?callback=?',function(){
        //出来获得的数据
      })

      jquery会自动生成一个全局函数来替换callback=?中问号,之后获取数据后会自动销毁,实际上起到一个临时代理函数的作用。$.getJSON会自动判断是否跨域,不跨域的话会调用普通的ajax方法;跨域的话,则会以异步加载js文件的形式来调用jsonp的回调函数。

      • jsonp的优缺点

      优点:它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的影响;它的兼容性更好,可以在古老的浏览器中运行,不要XMLHttpRequest或ActiveX的支持,在请求完毕后可以通过调用callback的方式回传结果。

      缺点:只支持get请求不支持post等其他类型的http请求。它只支持跨域http请求这种情况,不能解决不同域的两个页面之间如何进行javascript调用的问题。

    2. window.name

      window对象的name属性是一个特别的属性,当该window的location发生变化,然后重新加载,它的name属性可以依然保持不变。该属性有一个特征:即在一个窗口的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限。

      根据window对象的name属性,我们可以在页面A中加载其他域的页面B,而页面B中用javascript把需要传递的数据赋值给window.name ,iframe加载完成之后(iframe.onload),页面A修改iframe的地址,将其变成同域的一个地址,然后就可以读取iframe中的window.name中的值(因为A中的window.name和iframe中的window.name互相独立,所以不能直接在A中获取window.name,而要通过iframe获取window.name)

      例如我们要在http://www.example.com/a.html页面通过a.html页面里的js获取另一个位于不同域上的页面www.cnblogs.com/data.html里的数据

      在data.html页面中,给当前的window.name设置一个a.html页面想要得到的数据值

      <script>
      window.name='我就是页面a.html想要的数据,所有可以转化成字符串来传递的数据都可以在这里使用,比如传递一个json数据'
      </script>

      在a.html页面中我们不能直接在a.html页面中通过修改window.location来载入data.html页面,在a.html页面中使用一个隐藏的ifrane来充当媒介,由iframe获取data.html的数据,然后a.html再去得到iframe获取到的数据。

      iframe只要把src设置成www.cnblogs.com/data.html,就可以获取data.html中通过window.name设置的数据,然后a.html想要得到iframe所获取的数据,也就是想要得到iframe的window.name的值,必须把iframe的src设置成a.html页面同一个域。

      如下:

      <!doctype html>
      <html>
      <head>
         <meta charset="utf-8"/>
         <title>window.name跨域</title>
         <script>
         function getData(){ //iframe载入data.html页面后悔执行此函数
         var iframe=document.getElementById("proxy");
      //这个时候a.html和iframe已经处于同一源了,可以互相访问
               alert(data);//成功获取data.html中的数据
         }
         iframe.src='b.htm';//这里的b.html为随便的一个页 面,只要与a.html同源就行了,目的是让a.html能访问到iframe里的东西
        }
        </script>
      </head>
      <body>
      <iframe id="proxy" src="http://www.cnblogs.com/data.html"
      style="display:none" onload="getData()"></iframe>

      这种方式适合单向的数据请求,而且协议简单,安全,不像jsonp那样不做限制地执行外部脚本。

    3. document.domain+iframe

      对于主域相同,子域不同的两个页面,可以通过设置document.domain的方法解决.具体的做法可以在http://www.a.com/a.htmlhttp://script.a.com/b.html两个文件中分别加上document.domain=’a.com’;然后通过a.html文件中创建一个iframe,去控制iframe的contentDocument,这样两个文件就可以交互了。需要注意的是document.domain的设置是有限制的,我们只能把document.domain设置成自身或者更高一级的父域,切主域必须相同。例如a.b.example.com中某个文档的document.domain可以设置成a.b。example.com、b.example.com、example.com中的某一个,但是不可以设置成c.a.b.example.com,也不能设置成baidu.com(主域不同了)。

      做法如下:

      http://www.a.com/a.html页面中设置document.domain:

      <iframe src="http://script.a.com/b.html"  id="iframe" onload="text()"></iframe>
      <script>
      document.domain='a.com';//设置成主域
      function test(){
      alert(document.getElementById('iframe').contentWindow);
      }
      </script>

      http://script.a.com/b.html

      <script>
      document.domain='a.com';// 在iframe中载入的这个面
      //也设置document.domain,与主页面的document.domain
      //相同
      </script>

      这样可以通过js访问到iframe中分各种属性和对象。

      另外需要注意的是,修改document.domain的方法只适用于不同子域的框架间的交互,如果你想在http://www.a.com/a.html页面中通过ajax直接请求http://script.a.com/b.html页面是不行的,如果你想通过ajax的方法去与不同子域的页面交互,除了使用jsonp的方法外,还可以用一个隐藏的iframe来做一个代理。

    4. HTML5的postMessage

      window.postMessage(message,targetorigin) 方法是html5引入的新特性,它可以用来向其他对象的window对象发送信息,无论这个window对象是属于同源还是不同源,目前IE8+,chrome,firefos,Opera等浏览器都支window.postMessage方法。

      在A页面中使用postMessage方法,如下:

      window.onload=function(){  
      var ifr=document.getElementById('ifr');  
      var targetOrigin="http://wwww.google.com";  ifr.contentWindow.postMessage('hello world!',targetOrigin);
      }

      postMessage的使用方法:

      otherWindow.postMessage(message,targetOrigin);

      其中otherWindow指目标窗口,也就是给哪个window发消息,是window.frames属性的成员或者由window.open方法创建的窗口。

      messgae:指要发送的信息

      targetOrigin:限定信息接收范围,若不限制则使用” * “。

      B页面通过message事件监听并接收消息:

      var onmessage = function(event){
         var data = event.data; //消息
         var origin=event.origin;//消息来源地址
         var source=event.source; //源window对象
         if(origin=="http://www.baidu.com"){
              console.log(data); //hello world!
         }
      };
      if(typeof window.addEventListener!='undefined'){
         window.addEventListener('message',onmessage,false)
      }else if(typeof window.addachEvent!='undefined'){
        //for ie
        window.attachEent('onmessage',onmessage);
      }
    5. 其他

      跨域的方法有很多,不同的应用场景可以选择不同的跨域方式。除了上面介绍的几种方法外,另外还有其他的跨域方式,比如:flash,服务器代理 ,利用iframe和location.hash等等。有兴趣的同学可以自己搜索,另外上面的参考链接中也有涉及到。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值