国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

【Geek議題】當(dāng)年那些風(fēng)騷的跨域操作

mengera88 / 1342人閱讀

摘要:同源策略年,同源政策由公司引入瀏覽器。標(biāo)簽不受同源策略限制,但只能發(fā)起請求。這一行為使得不同域的特定文檔可以讀取該屬性值,因此可以繞過同源策略并使跨域消息通信成為可能。

前言

現(xiàn)在cross-origin resource sharing(跨域資源共享,下簡稱CORS)已經(jīng)十分普及,算上IE8的不標(biāo)準(zhǔn)兼容(XDomainRequest),各大瀏覽器基本都已支持,當(dāng)年為了前后端分離、iframe交互和第三方插件開發(fā)而頭疼跨域是時代已經(jīng)過去,但當(dāng)年為了跨域無所不用其極的風(fēng)騷操作卻依然值得學(xué)習(xí)。
本篇文章不是從實用的角度考量這些舊時代的跨域手段,而是更偏向理論的闡述,并引發(fā)對瀏覽器安全的思考,因為跨域?qū)嶋H上也是各類攻擊的核心。
本人個人能力有限,歡迎大牛一起討論,批評指正。

同源策略

1995年,同源政策由Netscape公司引入瀏覽器。目前,所有瀏覽器都實行這個安全策略。
核心是確保不同源提供的文件(資源)之間是相互獨立的。換句話說,只有當(dāng)不同的文件腳本是由相同的域、端口、HTTP協(xié)議提供時,才沒有特殊的限制。特殊限制可以細(xì)分為兩個方面:

對象訪問限制:主要體現(xiàn)在iframe,如果父子頁面的源是不同的,那就不可以訪問對方的DOM方法和屬性(包括Cookie、LocalStorage和IndexDB等)。不同來源便拋出異常。

網(wǎng)絡(luò)訪問限制:主要體現(xiàn)在AJAX請求,如果發(fā)起的請求目標(biāo)源與當(dāng)前頁面不同,瀏覽器就會限制了發(fā)起跨站請求,或攔截返回的請求。

一個表格看懂什么是同源?

origin(URL) result reason
http://example.com success 協(xié)議,域名和端口號80均相同
http://example.com:8080 fail 端口不同
https://example.com fail 協(xié)議不同
http://sub.example.com fail 域名不同

至于為什么說這是個安全策略?
這個就要提到cookie-session機(jī)制,眾所周知HTTP是無狀態(tài)協(xié)議,而服務(wù)器如何知曉用戶的登錄狀態(tài)?傳統(tǒng)上是使用了cookie-session這一機(jī)制,也就是服務(wù)器為每個訪問者生成了一個session標(biāo)識,而session標(biāo)識會被服務(wù)器包含在應(yīng)答頭中返回,瀏覽器解析到應(yīng)答頭中的set-cookie就把這串session標(biāo)識保存到本地cookie中,利用cookie每次請求同一個域都會帶上的特性,服務(wù)器器就能知曉當(dāng)前的用戶登錄狀態(tài)。
所以如果讓瀏覽器向不同源發(fā)起請求,就會造成很大的危險。比如用戶登錄了銀行的網(wǎng)站A,也就是說A站已經(jīng)在瀏覽器留下了cookie,這時候用戶又訪問了B站,如果能在B站頁面上發(fā)起A站的請求,就相當(dāng)于B站可以冒充用戶,在A站為所欲為。
由此可見,"同源策略"是必需的,否則cookie可以共享,互聯(lián)網(wǎng)就毫無安全可言了。

跨域方案

同源策略提出的時代還是傳統(tǒng)MVC架構(gòu)(jsp,asp)盛行的年代,那時候的頁面靠服務(wù)器渲染完成了大部分填充,內(nèi)容也比較簡單,開發(fā)者也不會維護(hù)獨立的API工程,所以其實跨域的需求是比較少的。
新時代前后端的分離和第三方JSSDK的興起,我們才開始發(fā)現(xiàn)這個策略雖然大大提高了瀏覽器的安全性,但有時很不方便,合理的用途也受到影響。比如:

獨立的API工程部署為了方便管理使用了獨立的域名;

前端開發(fā)者本地調(diào)試需要使用遠(yuǎn)程的API;

第三方開發(fā)的JSSDK需要嵌入到別人的頁面中使用;

公共平臺的開放API。

于是乎,在沒有標(biāo)準(zhǔn)規(guī)范的時代,如何解決這些問題的跨域方案就被紛紛提出,可謂百家爭鳴,其中不乏令人驚嘆的騷操作,這樣的極客精神依然值得我們敬佩和學(xué)習(xí)。

JSON-P

JSON-P是各類跨域方案中流行度較高的一個,現(xiàn)在在某些要兼容舊瀏覽器的環(huán)境下還會被使用,著名的jQuery也封裝其方法。請勿見名知義,名字中的P是padding“帶填充”的意思,這個方法在通信過程中使用的并不是普通的json,而是自帶填充功能的JavaScript腳本
如何理解“自帶填充功能的JavaScript腳本”,看看下面的例子或許比較簡單,如果一個js文件里這樣寫并被引入,則全局下就會有data對象,也就是說利用js腳本的引入和解析可以用來傳遞數(shù)據(jù),如果把js腳本換成函數(shù)運(yùn)行命令豈不是可以調(diào)用全局函數(shù)了。這就是JSON-P方法的核心思想,它填充的是全局函數(shù)的數(shù)據(jù)。

var data = {
  a: 1,
  b: 2
}
【PS】

// 定義回調(diào)函數(shù)
function getTheAnimal(data){
    var myAnimal = data.animal;
}
// 新建標(biāo)簽
var script = document.createElement("script");
script.type = "text/javascript";
// 常用的在url參數(shù)部分跟服務(wù)器約定號回調(diào)函數(shù)名
script.src = "http://demo.com/animal.json?callback=getTheAnimal";
document.getElementByTagName("head")[0].appendChild(script);

總結(jié)

優(yōu)點:

簡單,有現(xiàn)成的工具庫(jQuery)支持;

支持上古級別的瀏覽器(IE8-)。

缺點:

只能是GET方法;

受瀏覽器URL最大長度2083字符限制;

無法調(diào)試,服務(wù)器錯誤無法檢測到具體原因;

有CSRF的安全風(fēng)險;

只能是異步,無法同步阻塞;

需要特殊接口支持,不能基于REST的API規(guī)范。

子域名代理

這個方法實際上是利用瀏覽器允許iframe內(nèi)的頁面只要是跟父頁面是同個一級域名下,就能被父頁面修改和調(diào)用的特點。也許你會疑問,上面講同源策略的表格中很明確二級域名不同也是算不同源,這豈不矛盾了?
這其實不矛盾,如果正常操作確實會被同源策略限制,但瀏覽器的document.domain允許網(wǎng)站將主機(jī)部分更改為原始值的后綴。這意味著,寄放在sub.example.com的頁面可以將它的源設(shè)置為example.com,但是并不能將其設(shè)置為alt.example.com或google.com。

【PS】這里有一個細(xì)節(jié),父子頁面均要設(shè)置document.domain才能被互相訪問,單一一個是無法跨域的。document.domain的特點:只能設(shè)置一次;只能更改域名部分,不能修改端口號和協(xié)議;重置源的端口為協(xié)議默認(rèn)端口。

原理及流程

新建一個子域,比如api.demo.com(頁面在主域名demo.com下);

子域下需要一個代理文件proxy.html,設(shè)置其document.domain = "demo.com",并可以包含發(fā)起ajax的工具;

所有API地址都是在api.demo.com;

把需要發(fā)請求的主域頁面設(shè)置其document.domain = "demo.com"

新建iframe標(biāo)簽鏈接到代理頁;

當(dāng)iframe內(nèi)的子頁面就緒時,父頁面就可以使用子頁面發(fā)起ajax請求。

// 最簡單的代理文件proxy.html


    
    
// 新建iframe
var iframe = document.createElement("iframe");
// 鏈接到代理頁
iframe.src = "http://api.demo.com/proxy.html";
// 代理頁就緒時觸發(fā)
iframe.onload = function(){
  // 由于代理頁已經(jīng)和父頁設(shè)置了相同的源,父的腳本可以調(diào)用代理頁的ajax工具;
  // 由于是在子頁面發(fā)起,其請求地址就跟子頁面同源了。
  iframe.contentWindow.jQuery.ajax({
    method: "POST",
    url: "http://api.demo.com/products",
    data: {
      product: id,
    },
    success: function(){
      document.body.removeChild(iframe);
      /*...*/
    }
  })
}
document.getElementsByTagName("head")[0].appendChild(iframe);

總結(jié)

優(yōu)點:

可以發(fā)送任意類型的請求;

可以使用基于REST的API規(guī)范。

缺點:

不太適合第三方API,給第二方使用較麻煩;

iframe對瀏覽器性能影響較大;

無法使用非協(xié)議默認(rèn)端口的API。

模擬form表單

form表單的target屬性可以指定一個iframe,使主頁面不跳轉(zhuǎn),而iframe內(nèi)跳轉(zhuǎn),所以這個方法的核心就是利用表單提交,并在iframe中獲取數(shù)據(jù)
要訪問iframe內(nèi)外頁面互訪也是必須設(shè)置同源,這點與子域代理是相似的;而iframe內(nèi)回調(diào)父頁面,又與JSON-P相似,可以說是兩個思路的合體版。
form表單提交后返回的是頁面,所以與JSON-P不同的是,返回的是包含了自帶填充功能的JavaScript腳本的頁面,說起來有點繞,簡單來說就是把JSON-P返回的腳本放到一個html頁面里自運(yùn)行。
相比子域代理的方法,它不需要代理頁

【PS】form表單提交的特點就是會導(dǎo)致整個頁面跳轉(zhuǎn),返回數(shù)據(jù)是在新的頁面上,這樣自然不會產(chǎn)生跨域的問題。

原理及流程

新建一個子域,比如api.demo.com(頁面在主域名demo.com下);

所有API地址都是在api.demo.com;

把需要發(fā)請求的主域頁面設(shè)置其document.domain = "demo.com"

先定義好父頁面上的回調(diào)函數(shù);

新建iframe標(biāo)簽并指定名字;

新建表單form標(biāo)簽,指定target為剛才的iframe,并添加數(shù)據(jù);

提交表單,iframe內(nèi)跳轉(zhuǎn),其中自運(yùn)行腳本調(diào)用了父頁面的回調(diào)函數(shù)。

// 新建并隱藏iframe
var frame = document.createElement("iframe");
iframe.name = "post-review";
frame.style.display = "none";

// 新建表單
var form = document.createElement("form");
form.action = "http://api.demo.com/products";
form.method = "POST";
form.target = "post-review";
// 添加數(shù)據(jù)
var score = document.createElement("input");
score.name = "score";
score.value = "5";
// 添加數(shù)據(jù)
var message = document.createElement("input");
message.name = "message";
message.value = "hello world";
// 把數(shù)據(jù)加到表單
form.appendChild(score);
form.appendChild(message);
// 渲染iframe和表單
document.body.appendChild(frame);
document.body.appendChild(form);
// 提交表單發(fā)起請求
form.submit();
// 完成清理元素
document.body.removeChild(form);
document.body.removeChild(frame);
// 最簡單返回html


    

總結(jié)

由于這個方法是JSON-P與子域名代理的結(jié)合版,可以說即擁有兩者的優(yōu)點,也保留了兩者一些缺點。

優(yōu)點:

可以發(fā)送任意類型的請求;

不需要代理頁;

支持上古級別的瀏覽器(IE8-)。

缺點:

不太適合第三方API,給第二方使用較麻煩;

iframe對瀏覽器性能影響較大;

無法使用非協(xié)議默認(rèn)端口的API;

需要特殊接口支持,不能基于REST的API規(guī)范。

window.name

這方法利用了window.name的特性:一旦被賦值后,當(dāng)窗口被重定向到一個新的URL時不會改變它的值。這一行為使得不同域的特定文檔可以讀取該屬性值,因此可以繞過同源策略并使跨域消息通信成為可能。

【PS】例子里演示的是發(fā)起get請求,只要把請求地址直接寫到src里就行了。如果想要發(fā)起其他類型的請求,可以類比采用模擬的form的方式進(jìn)行改造。

原理及流程

新建iframe,使用iframe訪問一個非同源的地址(發(fā)請求);

當(dāng)頁面加載完成后,iframe內(nèi)腳本給window.name屬性賦值,這時父頁面還是不能讀取到子頁面的屬性(因為不同源);

iframe自身回調(diào)到一個同源的地址(可能只是個空白頁),這時候window.name沒有改變;

父頁面順利讀取window.name的值。

// 新建iframe
var iframe = document.createElement("iframe");
var body = document.getElementByTagName("body");
// 隱藏iframe并鏈接地址
iframe.style.display = "none";
iframe.src = "http://api.demo.com/server.html?id=1";
// 因為需要兩次跳轉(zhuǎn),這里有個完成標(biāo)記
var done = fasle;
// 這里會觸發(fā)至少兩次,一次由于非同源是取不到值的。
iframe.onload = iframe.onreadystatechange = function(){
    if(! this.readyState && (iframe.readyState !== "complete" || done)){
        return;
    }
    console.log("Listening");
    var name = iframe.contentWindow.name;
    if(name){
        console.log(iframe.contentWindow.name);
        done = true;
    }
};
body.appendChild(iframe);
// 最簡單返回html


    
    

總結(jié)

優(yōu)點:

可以發(fā)送任意類型的請求;

不需要設(shè)置子域名。

缺點:

iframe對瀏覽器性能影響較大;

需要特殊接口支持,不能基于REST的API規(guī)范;

每當(dāng)你想要獲取一條新的消息時都不得不發(fā)起兩次網(wǎng)絡(luò)請求,網(wǎng)絡(luò)成本大;

需要準(zhǔn)備空白頁,對它的訪問是無意義的,影響流量統(tǒng)計。

window.hash

這個方法利用了location的特性:不同域的頁面,可以寫不可讀。而只改變哈希部分(井號后面)不會導(dǎo)致頁面跳轉(zhuǎn)。也就是可以讓父、子頁面互相寫對方的location的哈希部分,進(jìn)行通訊。

原理及流程

新建iframe,使用iframe訪問一個非同源的地址(發(fā)請求),參數(shù)里帶上父頁面url;

當(dāng)頁面加載完成后,iframe內(nèi)腳本設(shè)置父頁面的url并在哈希部分帶上數(shù)據(jù);

父頁面的腳本循環(huán)檢查哈希值的變化,如果檢查到有值就取值并清空哈希值;

【PS】父頁面會循環(huán)檢查哈希是否改變來讀取值,因為這種降級方案的使用環(huán)境一般是不會有hashchange事件的。演示里是最簡單的get方法,如果想要發(fā)起其他類型的請求,可以類比采用模擬的form的方式進(jìn)行改造,但記住不要丟失父頁面的url。

// 獲取當(dāng)前url
var url = window.location.href;
// 新建iframe
var iframe = document.createElement("iframe");
// 隱藏iframe并設(shè)置鏈接,把當(dāng)前url帶上
iframe.style.display = "none";
iframe.src = "http://api.demo.com/server.html?id=1&url=" + encodeURIComponent(url);

var body = document.getElementByTagName("body")[0];
body.appendChild(iframe);
// 循環(huán)監(jiān)聽處理
var listener = function(){
    // 讀取
    var hash = location.hash;
    // 還原
    if(hash && hash !== "#"){
        console.log(hash.replace("#", ""));
        window.loacation.href = url + "#";
    }
    // 繼續(xù)監(jiān)聽
    setTimeout(listener, 100);
};
listener();
// 最簡單返回html


    
    

總結(jié)

優(yōu)點:

可以發(fā)送任意類型的請求;

不需要設(shè)置子域名。

缺點:

iframe對瀏覽器性能影響較大;

需要特殊接口支持,不能基于REST的API規(guī)范;

循環(huán)檢查哈希需要消耗性能;

返回數(shù)據(jù)受瀏覽器URL最大長度2083字符限制。

現(xiàn)代的標(biāo)準(zhǔn)

W3C的標(biāo)準(zhǔn)化跨域方案,讓現(xiàn)代瀏覽器跨域已經(jīng)不是什么復(fù)雜的事。這部分網(wǎng)上資料已經(jīng)很多,這里就只是簡單介紹。

CORS

CORS是一個W3C標(biāo)準(zhǔn),全稱是"跨域資源共享"(Cross-origin resource sharing)。
它允許瀏覽器向跨源服務(wù)器,發(fā)出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。

CORS參考文檔
跨域資源共享 CORS 詳解

postMessage

H5的window.postMessage為瀏覽器帶來了一個安全的。基于事件的消息api。
只要是window對象,基本都可以使用這個方法,也就是說window.name、window.hash這類風(fēng)騷的操作都已成為降級方案。

postMessage參考文檔

安全問題

上述的各類非標(biāo)準(zhǔn)的騷操作,都算是對同源策略的破解辦法,在方便開發(fā)者完成跨域目的的同時,各類惡意的攻擊者也自然會利用這些方案為非作歹。
其中子域名代理的風(fēng)險最低,因為需要服務(wù)器設(shè)置特定的子域名,也就是已經(jīng)是兩個源的協(xié)商結(jié)果,一般黑客是難以模擬的。
風(fēng)險最高的要算JSON-P的方案,因為這是任何客戶端都可隨意使用的辦法,CSRF攻擊的核心也是利用了特定標(biāo)簽的跨域性發(fā)起請求,所以JSON-P最好用在無用戶狀態(tài)的低安全性API上。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/94045.html

相關(guān)文章

  • Geek議題當(dāng)年那些風(fēng)騷跨域操作

    摘要:同源策略年,同源政策由公司引入瀏覽器。標(biāo)簽不受同源策略限制,但只能發(fā)起請求。這一行為使得不同域的特定文檔可以讀取該屬性值,因此可以繞過同源策略并使跨域消息通信成為可能。 前言 現(xiàn)在cross-origin resource sharing(跨域資源共享,下簡稱CORS)已經(jīng)十分普及,算上IE8的不標(biāo)準(zhǔn)兼容(XDomainRequest),各大瀏覽器基本都已支持,當(dāng)年為了前后端分離、if...

    Worktile 評論0 收藏0
  • Geek議題】合理的VueSPA架構(gòu)討論(上)

    摘要:下面也是以模塊的模塊集為例,可以發(fā)現(xiàn)和路由有一些不同就是這里為了防止模塊跟全局耦合,運(yùn)用函數(shù)式編程思想類似于依賴注入,將全局的實例作為函數(shù)參數(shù)傳入,再返回出一個包含的對象,這個導(dǎo)出的對象將會被以模塊名命名,合并到全局的集中。 前言 web前端發(fā)展到現(xiàn)代,已經(jīng)不再是嚴(yán)格意義上的后端MVC的V層,它越來越向類似客戶端開發(fā)的方向發(fā)展,已獨立擁有了自己的MVVM設(shè)計模型。前后端的分離也使前端人...

    worldligang 評論0 收藏0
  • Geek議題】合理的VueSPA架構(gòu)討論(上)

    摘要:下面也是以模塊的模塊集為例,可以發(fā)現(xiàn)和路由有一些不同就是這里為了防止模塊跟全局耦合,運(yùn)用函數(shù)式編程思想類似于依賴注入,將全局的實例作為函數(shù)參數(shù)傳入,再返回出一個包含的對象,這個導(dǎo)出的對象將會被以模塊名命名,合并到全局的集中。 前言 web前端發(fā)展到現(xiàn)代,已經(jīng)不再是嚴(yán)格意義上的后端MVC的V層,它越來越向類似客戶端開發(fā)的方向發(fā)展,已獨立擁有了自己的MVVM設(shè)計模型。前后端的分離也使前端人...

    pepperwang 評論0 收藏0
  • Geek議題】合理的VueSPA架構(gòu)討論(下)

    摘要:接上篇議題合理的架構(gòu)討論上傳送門。處理思路如下使用上面定義的方法獲取如果能獲取到則說明有有效的,則時候即可跳轉(zhuǎn)到目標(biāo)頁如果獲取到空字符串,則說明無效或不存在,跳轉(zhuǎn)至登錄頁面。 接上篇《【Geek議題】合理的VueSPA架構(gòu)討論(上)》傳送門。 自動化維護(hù)登錄狀態(tài) 登錄狀態(tài)標(biāo)識符跟token類似,都是需要自動維護(hù)有效期,但也有些許不同,獲取過程只在用戶登錄或注冊的時候,不需要自動獲取。 ...

    mindwind 評論0 收藏0
  • Geek議題】合理的VueSPA架構(gòu)討論(下)

    摘要:接上篇議題合理的架構(gòu)討論上傳送門。處理思路如下使用上面定義的方法獲取如果能獲取到則說明有有效的,則時候即可跳轉(zhuǎn)到目標(biāo)頁如果獲取到空字符串,則說明無效或不存在,跳轉(zhuǎn)至登錄頁面。 接上篇《【Geek議題】合理的VueSPA架構(gòu)討論(上)》傳送門。 自動化維護(hù)登錄狀態(tài) 登錄狀態(tài)標(biāo)識符跟token類似,都是需要自動維護(hù)有效期,但也有些許不同,獲取過程只在用戶登錄或注冊的時候,不需要自動獲取。 ...

    RyanHoo 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<