跨源通訊

跨源限制
在瀏覽器裏
對源(url協議,主機名,端口號)不一樣的通訊進行限制,在web領域 爲了確保安全,只有同源的通訊才能被容許進行,稱爲同源策略
雖然能夠在html裏使用iframe以實如今一個頁面中同時顯示來自不一樣域的文檔,不過js仍然只能訪問同一源的文檔
若是文檔的url和iframe的不一樣,則沒法經過文檔中包含的js對iframe內的dom進行操做,而iframe內的js也沒法操做文檔裏的dom
若是不這樣 ,就會發生諸如不一樣域的cookie可以互相訪問等安全問題javascript

對於XMLHttpRequest來講,同源策略的含義是,一個XMLHttpRequest對象只能發送至一個特定的服務器,即提供了使用該XMLHttpRequest對象的文檔下載服務器
跨源通訊php

 

js裏的跨源通訊
JSONP
iframe攻擊
window.postMessage()
XMLHttpRequest level 2css

1.JSONP
利用script標籤的src將其它域的js文件載入,若是在此處動態建立script標籤的話,就能實現對其它域中數據的動態讀取
不過僅僅是取得了數據,還沒法在客戶端使用。所以產生jsonp(json with padding ,padding指向json數據中添加函數名)
服務端會對數據添加函數名後返回
代碼示例html

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <script src="//cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
</head>
<body>
<script>
var url="http://b.cn/do.php?callback=foo";
//注意 foo函數的定義要先於 引入 url裏的內容
function foo(res){
    console.log(res);
    console.log(res.a);
}

function loadData(url){
    var elem=document.createElement('script');
    elem.src=url;
    document.getElementsByTagName('head')[0].appendChild(elem);

}
loadData(url);
</script>
</body>
</html>

b.cn/do.phpjava

<?php
$arr=['a'=>'ajax','b'=>'bbc'];
$callback=$_GET['callback'];
$json=$callback."(".json_encode($arr).");";
echo $json;   //foo({"a":"ajax","b":"bbc"});
?>

請求的內容是執行代碼的內容,在客戶端是定義聲明部分
jsonp的缺點
沒法在post請求類型中使用
只能作到動態建立script標籤並讀取數據而沒法從客戶端發出數據jquery

2. XMLHttpRequest level 2
XMLHttpRequest沒法跨源通訊
在XMLHttpRequest level2中 只要服務器端許可就能夠實現web

a.cn/a.htmlajax

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <script src="//cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
</head>
<body>
<div class="btn" style="cursor: pointer;text-align:center;width: 100px;height: 50px;line-height:50px;color:white;background: green">click</div>
<script>
$(function(){
    $(".btn").click(function(){
        var xhr=new XMLHttpRequest();
        xhr.onreadystatechange=function(){
            var state=xhr.readyState;
            if(state==4){
                console.log(xhr.getAllResponseHeaders());
            }
        }
        xhr.open('GET','http://b.cn/do.php?a=1&b=2');
        xhr.withCredentials=true; 
        //默認不發送cookie的,當設個參數設置爲true服務端 Access-Control-Allow-Origin 必須明確指定 不可爲* 並且必須設置 header('Access-Control-Allow-Credentials:true');
        xhr.setRequestHeader("content-type",'multipart/form-data');
//      xhr.setRequestHeader("content-type",'application/x-www-form-urlencoded');
        xhr.send('p1=1');

    });

});

</script>

</body>
</html>
http://b.cn/do.php
代碼
<?php
header('Access-Control-Allow-Origin:http://a.cn');
header('Access-Control-Allow-Credentials:true');
header('Access-Control-Allow-Methods:POST');
var_dump($_POST);
var_dump($_GET);
var_dump(file_get_contents("php://input"));
var_dump($_COOKIE);

 關於跨源發送cookie 算法

xhr.withCredentials=true; json

這裏跨源指的是 跨的二級的域,根域必須相同,並且cookie的域必須是根域 

好比 a.a.cn能夠經過這裏所說的跨源 在向b.a.cn發送ajax請求時 帶上 .a.cn下的cookie

不要覺得 域在.a.cn下的cookie ,a.a.cn在向b.a.cn發請求時 會自動帶上

也不要認爲cookie的跨源能跨根域,是不可能的



3.postMessage()

window.postMessage 是一個安全的跨源通訊的方法。通常狀況下,當且僅當執行腳本的頁面使用相同的協議(一般都是 http)、相同的端口(http默認使用80端口)和相同的 host(兩個頁面的document.domain 的值相同)時,才容許不一樣頁面上的腳本互相訪問。 window.postMessage 提供了一個可控的機制來安全地繞過這一限制,當其在正確使用的狀況下。

 

調用 window.postMessage時,將分發一個MessageEvent事件到目標窗口, 在全部掛起必須執行的腳本完成後.  (例如:當一個事件處理程序調用window.postMessage時,仍剩餘事件處理程序,  先前的掛起等待超時等)。MessageEvent 有消息類型,它被設置爲第一個參數值提供給window.postMessage的data屬性, 對應的window調用window.postMessage的時候,window.postMessage主文檔的來源的origin屬性被稱爲源屬性,指哪一個調用window.postMessage的窗口。 (事件的其餘標準屬性都存在與對應的預期值。)

 

語法

otherWindow.postMessage(message, targetOrigin);
 
otherWindow
其餘窗口的一個引用,好比iframe的contentWindow屬性、執行window.open返回的窗口對象、或者是命名過或數值索引的window.frames
message
將要發送到其餘 window的數據,將會被結構化克隆算法序列化。這意味着你可不受什麼限制的安全傳送數據對象給目標窗口而無需本身序列化
targetOrigin
經過窗口的origin屬性來指定哪些窗口能接收到消息事件,其值能夠是字符串"*"(表示無限制)或者一個URI。在發送消息的時候,若是目標窗口的協議、主機地址或端口這三者的任意一項不匹配targetOrigin提供的值,那麼消息就不會被髮送;只有三者徹底匹配,消息纔會被髮送。這個機制用來控制消息能夠發送到哪些窗口;例如,當用postMessage傳送密碼時,這個參數就顯得尤其重要,必須保證它的值與這條包含密碼的信息的預期接受者的orign屬性徹底一致,來防止密碼被惡意的第三方截獲。若是你明確的知道消息應該發送到哪一個窗口,那麼請始終提供一個有確切值的targetOrigin,而不是*。不提供確切的目標將致使數據泄露到任何對數據感興趣的惡意站點
a.cn/a.html
<!DOCTYPE html>
<html>
<head>
    <title>Post Message</title>
</head>
<body>
<div style="width:200px; float:left; margin-right:200px;border:solid 1px #333;">
    <div id="color">Frame Color</div>
</div>
<div>
    <iframe id="child" src="http://b.cn/b.html"></iframe>
</div>

<script type="text/javascript">
    window.onload=function(){
        window.frames[0].postMessage('getcolor','http://b.cn');
    }

    window.addEventListener('message',function(e){
        console.log('a:',e);
        var color=e.data;
        document.getElementById('color').style.backgroundColor=color;
    },false);
</script>
</body>
</html>

b.cn/b.html

<!doctype html>
<html>
<head>
    <style type="text/css">
        html,body{
            height:100%;
            margin:0px;
        }
    </style>
</head>
<body style="height:100%;">
<div id="container" onclick="changeColor();" style="widht:100%; height:100%; background-color:rgb(204, 102, 0);">
    click to change color
</div>
<script type="text/javascript">
    var container=document.getElementById('container');

    window.addEventListener('message',function(e){
        if(e.source!=window.parent) return;
        var color=container.style.backgroundColor;
        window.parent.postMessage(color,'*');
    },false);

    function changeColor () {
        var color=container.style.backgroundColor;
        if(color=='rgb(204, 102, 0)'){
            color='rgb(204, 204, 0)';
        }else{
            color='rgb(204,102,0)';
        }
        container.style.backgroundColor=color;
        window.parent.postMessage(color,'*');
    }
</script>
</body>
</html>
相關文章
相關標籤/搜索