Stay Hungry,Stay Foolish!

跨域访问实践

 

同源策略

An origin is defined by the scheme, host, and port of a URL. Generally speaking, documents retrieved from distinct origins are isolated from each other.

https://developer.mozilla.org/zh-CN/docs/Same-origin_policy_for_file:_URIs

http://www.w3.org/Security/wiki/Same_Origin_Policy

 

对于一些同源策略, 是HTML5新定义, 是否可使用,可以查询如下网站:

http://caniuse.com/

 

iframe方式嵌入页面的操作实验

javascript的同源策略,见如下文章:

https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy?redirectlocale=zh-CN&redirectslug=JavaScript%E7%9A%84%E5%90%8C%E6%BA%90%E7%AD%96%E7%95%A5 

只有在 协议 域名 和 端口 完全一致的情况下, 才认为, 两个页面对应同一个源。

 

下面使用iframe和js api,构造跨域访问实例。

js api 为 iframe.contentDocument, 父亲页面通过此js api访问iframe内嵌页面的内容,  详细见下文:

https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement

 

父亲页面为: a.html, 内嵌一个 iframe, 引用b.html(域名为 localhost)

父亲页面加载后, 访问内嵌页面的 ID为binput 输入框的值。

<html>
<body>
<h1>
hi, this is a.html, frame below show b.html
</h1>
<iframe src="http://localhost/b.html"></iframe>
<script type="text/javascript">
        window.onload = function(){
                console.log("a.html loaded");
                var frame = document.getElementsByTagName("iframe");
                console.log("frame src="+frame[0].src);
                var binput = frame[0].contentDocument.getElementById("binput");
                console.log("b.html binput value="+binput.value);
        }

</script>
</body>
</html>
 
内嵌页面:b.html
其中有 binput 输入框。
<html>
<body>
<h1>
hi, this is b.html. this page call by localhost domain.
</h1>
<input id="binput" value="binput"/>
</body>
</html>

 

实验结果:

使用http://localhost/a.html访问, 查看控制台, 可以发现 a可以访问b的binput。

使用http://127.0.0.1/a.html访问, 查看控制台, 可以发现浏览器有报错, (b.html使用localhost域名访问),chrome浏览器访问报错如下:

 a.html loaded a.html:9
frame src=http://localhost/b.html a.html:11
Uncaught SecurityError: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "http://127.0.0.1" from accessing a frame with origin "http://localhost". Protocols, domains, and ports must match. a.html:12

 

CORS实践

ajax不能跨域访问, 同iframe跨域访问相同, 都是受同源策略影响。

CORS 为ajax跨域访问的一种解决方案,详细见下文:

 http://www.cnblogs.com/Darren_code/p/cors.html

CORS W3C规范:

http://www.w3.org/TR/cors/

 

网上介绍的例子, 可见 ajax 请求跨域,是现到达服务器,然后根据响应来决定是否在客户端显示响应的。

http://blog.csdn.net/hfahe/article/details/7730944

 

服务器: index.php 

添加跨域可访问的 header 头,可以任何网站访问:

<?php
 header("Access-Control-Allow-Origin:*");
 
 echo "hello ".$_SERVER['HTTP_HOST'];

 exit;
?>
Something is wrong with the XAMPP installation :-(

 

客户端: index.html

其中的ajax使用127.0.0.1域名访问index.php

<html>
<head> 
        <style>

        </style>
        
</head> 
<body>
        <h1>hello world!</h1>
         <input type="text" value="test"/>
         <input type="button" value="button"/>
<script type='text/javascript'> 
    function createCORSRequest(method, url) {
      var xhr = new XMLHttpRequest();
      if ("withCredentials" in xhr) {
        // 此时即支持CORS的情况
        // 检查XMLHttpRequest对象是否有“withCredentials”属性
        // “withCredentials”仅存在于XMLHTTPRequest2对象里
        xhr.open(method, url, true);
     
      } else if (typeof XDomainRequest != "undefined") {
     
        // 否则检查是否支持XDomainRequest,IE8和IE9支持
        // XDomainRequest仅存在于IE中,是IE用于支持CORS请求的方式
        xhr = new XDomainRequest();
        xhr.open(method, url);
     
      } else {
     
        // 否则,浏览器不支持CORS
        xhr = null;
     
      }
      return xhr;
    }
     
    var xhr = createCORSRequest('GET', "http://127.0.0.1/index.php");
    if (!xhr) {
      throw new Error('CORS not supported');
    }
    
    xhr.onreadystatechange = function processRequest()
    {
        if (xhr.readyState == 4) // 判断对象状态
        {
           if (xhr.status == 200)  // 请求结果已经成功返回
           {
              alert(xhr.responseText);
           }
        }
    };
    xhr.send();
</script>
</body>
</html>

 

 如果页面使用 http://127.0.0.1/index.html访问, ajax属于站内访问,可以执行成功,

如果页面使用 http://localhost/index.html访问, ajax属于跨站访问,执行报错:

XMLHttpRequest cannot load http://127.0.0.1/index.php. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.  

  

nginx配置跨域

http://enable-cors.org/server_nginx.html
https://gist.github.com/michiel/1064640
 
其他Server配置跨域

 

安全的跨源文档通信(Cross Document Messaging)

postMessage

https://developer.mozilla.org/zh-CN/docs/Web/API/window.postMessage

http://www.ibm.com/developerworks/cn/web/1301_jiangjj_html5message/index.html

示例来源用途第二个网址:

 服务器localhost/a.php使用postMessage传送 消息到 内嵌的不同域页面 127.0.0.1/b.php:

 <html> 
 <head> 
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
 <title>Test Cross-domain communication using HTML5</title> 
 <script type="text/JavaScript"> 
     function sendIt(){ 
         // 通过 postMessage 向子窗口发送数据
         document.getElementById("otherPage").contentWindow 
             .postMessage( 
                 document.getElementById("message").value, 
                "http://127.0.0.1/"
             ); 
     } 
 </script> 
 </head> 
 <body> 
     <!-- 通过 iframe 嵌入子页面 --> 
     <iframe src="http://127.0.0.1/b.php" 
                 id="otherPage"></iframe> 
     <br/><br/> 
     <input type="text" id="message"><input type="button" 
             value="Send to child.com" onclick="sendIt()" /> 
 </body> 
 </html>

 

b.php

<html> 
 <head> 
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
 <title>Web page from child.com</title> 
 <script type="text/JavaScript"> 
     //event 参数中有 data 属性,就是父窗口发送过来的数据
     window.addEventListener("message", function( event ) { 
         // 把父窗口发送过来的数据显示在子窗口中
       document.getElementById("content").innerHTML+=event.data+"<br/>"; 
     }, false ); 

 </script> 
 </head> 
 <body> 
     Web page from http://127.0.0.1 
     <div id="content"></div> 
 </body> 
 </html>

 

 

阻止页面被iframe内嵌

使用报文头标识 : X-Frame-Options

https://developer.mozilla.org/en-US/docs/Web/HTTP/X-Frame-Options

 

详细解释见下面说明:

Using X-Frame-Options

There are three possible values for X-Frame-Options:

DENY
The page cannot be displayed in a frame, regardless of the site attempting to do so.
SAMEORIGIN
The page can only be displayed in a frame on the same origin as the page itself.
ALLOW-FROM uri
The page can only be displayed in a frame on the specified origin.

 

a.php 内嵌 b.php , 使用locahost引用:

<html>
<body>
<h1>
hi, this is a.php, frame below show b.php using domain localhost
</h1>
<iframe src="http://localhost/b.php"></iframe>
</body>
</html>

b.php, 通过头decalare内嵌权限:

<?php
//header("X-Frame-Options: DENY"); // 不管地址栏访问 localhost/a.php 还是 127.0.0.1/a.php,都不能显示b.php
//header("X-Frame-Options: SAMEORIGIN"); // 只有使用 localhost/a.php,才能能显示b.php
header("X-Frame-Options: ALLOW-FROM 127.0.0.1"); // 即使使用 127.0.0.1/a.php,也能显示b.php
?>

<html>
<body>
<h1>
hi, this is b.html. this page call by localhost domain.
</h1>
<input id="binput" value="binput"/>
</body>
</html>

 

posted @ 2014-08-19 00:23  lightsong  阅读(29175)  评论(0编辑  收藏  举报
Life Is Short, We Need Ship To Travel