摘要:簡單地理解就是因為同源策略的限制,它是瀏覽器為了安全性考慮一種非常重要的策略,域名下的無法操作或是域名下的對象。同源策略會限制以下三種行為和無法讀取。例如中可以引用等資源,此類操作不受同源策略限制。
同源策略
同源策略same origin policy中的重要內容就是URL(uniform resource locator),統一資源定位符,俗稱網址。URL中的resource資源就是css,js,html,img等內容。
源包括當前頁面的域名、協議、端口號。http協議默認端口是80,https協議默認端口是443。同源策略是瀏覽器的一個安全機制功能,Same Origin Policy,同源就是當協議、域名、端口號一致時就是同源。不同源的客戶端腳本在沒有明確授權下,不能讀寫對方的資源。簡單地理解就是因為同源策略的限制,它是瀏覽器為了安全性考慮一種非常重要的策略,a.com 域名下的js無法操作b.com或是c.a.com域名下的對象。更詳細的說明可以看下表:
瀏覽器基于用戶的隱私安全目的,防止惡意網站竊取數據(只是瀏覽器有這個同源策略設置,但是用命令行curl請求某個跨域地址時能得到相應結果),不允許不同域名的網站之間互相調用ajax XHR對象,只是不允許XHR對象,對其他的圖片、js腳本、css腳本還是可以通過標簽跨域調用。所以css/js/img可以跨域請求(即引用),AJAX不能請求跨域的資源。
curl http://www.abc.com 用這個命令獲得了http://www.abc.com指向的頁面,同樣,如果這里的URL指向的是一個文件或者一幅圖都可以直接下載到本地。如果下載的是HTML文檔,那么缺省的將不顯示文件頭部,即HTML文檔的header。要全部顯示,請加參數 -i,要只顯示頭部,用參數 -I。任何時候,可以使用 -v 命令看curl是怎樣工作的,它向服務器發送的所有命令都會顯示出來。為了斷點續傳,可以使用-r參數來指定傳輸范圍。
【1】 Cookie、LocalStorage 和 IndexedDB 無法讀取。Cookie 是服務器寫入瀏覽器的一小段信息,只有同源的網頁才能共享。
【2】 DOM 無法獲得。
【3】 AJAX 請求無效(可以發送,但瀏覽器會拒絕接受響應)。
主域名 abc.com
www.abc.com //www是子域名
bbs.abc.com //bbs是子域名
beijing.bbs.abc.com //beijing.bbs是子域名
haidian.beijing.bbs.abc.com //haidian.beijing.bbs是子域名
主域名是不帶www的域名,例如a.com,主域名前面帶前綴的通常都為二級域名或多級域名,例如www.a.com其實是二級域名。
解決跨域問題的兩個前提特別注意:
第一,如果是協議和端口造成的跨域問題“前端”無法解決。
第二:在跨域問題上,域僅僅是通過“URL的首部”來識別而不會去嘗試判斷相同的ip地址對應著兩個域或兩個域是否在同一個ip上。比如在host文件中可將兩個不同域名綁定到同一個IP地址上形成跨域。
“URL的首部”可在console.log控制臺中用window.location.方法名獲取
跨域就是用某種方法突破同源策略的限制,實現獲取其他域中的資源。實現跨域一般有四種方法:
1.JSONP實現跨域JSONP(json with padding)方式, 通過script標簽請求資源,允許用戶在scr地址中傳遞一個callback參數(callback=abc)即將預先定義好的回調函數名以查詢字符串的形式傳遞給服務端,服務端收到請求后會將要返回的數據用這個callback參數(abc)包裹住再返回,即將請求傳入的參數abc作為函數名來包裹住要返回的JSON數據,比如abc(JSON),這樣客戶端在收到服務端返回的abc(JSON)文件后默認用JS解析執行。通過JSONP就可以隨意定制自己的函數來自動處理返回數據了。
jsonp的原理:雖然瀏覽器默認禁止了跨域訪問,但并不禁止在頁面中script標簽引用其他域下的JS文件,比如線上jquery庫,并可以自由執行引入的JS文件中的function(包括操作cookie、Dom等等)。根據這一點,可以方便地通過動態創建script節點的方法來實現完全跨域的通信。例如a.com/index.html中可以引用b.com/main.js、b.com/style.css、b.com/logo.png等資源,此類操作不受同源策略限制。實際操作中如果在a.com下用ajax去請求(讀寫)b.com下的內容會被同源策略阻止,但a.com里如果引用了b.com/main.js,雖然可以引用,但當這個引用的js文件(在a.com下引用)去讀寫(ajax)b.com的資源時一樣會提示ajax錯誤。注意讀寫和引用有本質區別的,受同源策略限制ajax不能(POST寫/GET讀)請求跨域內容,但可以通過script引用的方式獲取目標域上js文件,如果在這個被引用的JS文件內存放數據,這樣就能從目標域獲取到數據了,這就是JSONP實現的原理。
JSONP與JSON沒有關系。JSON是規定語法的一種字符串的寫法。JSONP(json with padding),這里的padding就是被請求的目標域B域返回的數據其外層包裹的A域預先定義好的函數+括號。JSONP就是動態的script,即A域前臺傳什么callback=abc給B域名后臺,B域就生成對應的abc方法,這個方法的執行過程是A域預先定義好的
jsonp的缺點:
1.安全問題,src引用是開放的,所以jsonp的資源都被所有人訪問到。解決方法是用jsonp中的token參數,通過A域和B域共用同一套cookie來驗證A的身份。
2.只能用GET方式不能用POST方式獲取數據即只能讀不能寫,因為是基于scr引用的,引用是get請求。
3.可被注入惡意代碼如?callback=alert(1); 這問題只能用正則過濾字符串的方法解決,過濾callback后的內容不能有括號之類的條件
JSONP的實現代碼如下:
1.定義數據處理函數
appendHtml(){ xxxxx }
2.創建script標簽,src的地址執行后端接口,最后加個參數callback=appendHtml.如:
var script=document.createElement("script") script.src="http://127.0.0.1/getNews?callback=appendHtml"
3.服務端在收到請求后,解析參數,計算返還數據,輸出 appendHtml(data) 字符串。
4.前臺頁面收到服務端返回的appendHtml(data)字符串所構建的script標簽,頁面加載這個script標簽時做為js執行。此時會調用appendHtml()函數,將data做為參數。
注意:JSONP實現的前提是后端必須有JSONP的API接口,即后端有將前端傳入的參數作為函數名包裹數據返回js文件的邏輯。如:
var data=[{"a":1,"b":2}] var cb=req.query.callback; if(cb){ res.send(`${cb}(JSON.stringify(${data}))`) }else{ res.send(`${data}`) }
需后臺配合,代碼如下圖
function jsonp(url,_callback){ var scriptNode=document.createElement("script") scriptNode.setAttribute("type","text/javascript") scriptNode.setAttribute("src",`${url}?callback=${_callback}`) document.head.appendChild(scriptNode) } function getMusic(content){ /*定義數據返回時所執行的回調函數*/ console.log(content.song[0]) var comeMusic=content.song[0], musicTitle=comeMusic.title, musicArtist=comeMusic.artist, imgSrc=comeMusic.picture, _src=imgSrc.match(/.[^@]*/g)[0] /*正則匹配返回的圖片地址*/ console.log(_src) imgNode.src=_src h3Node.innerText=musicTitle h6Node.innerText=musicArtist }
調用jsonp函數:
jsonp(http://www.aaa.com,getMusic)
CORS允許瀏覽器向跨域服務器發出XMLHttpRequest請求,突破了AJAX只能同源使用的限制。CORS需要瀏覽器和服務器同時支持,目前,所有瀏覽器都支持該功能,IE瀏覽器不能低于IE10。CORS原理:瀏覽器一旦發現AJAX請求跨源,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會有感覺。只要服務器實現了CORS接口,就可以跨源通信。
以nodejs server-mock后臺為例:
res.header("Accept-Control-Allow-Origin","http://www.a.com:8080")//只允許http://www.a.com:8080這個源發起的請求
res.header("Accept-Control-Allow-Origin","*")//允許所有源發起的請求
瀏覽器將跨域請求分為兩類
簡單請求(simple request),同時滿足以下兩個條件
【1】請求方法是HEAD/GET/POST之一
【2】HTTP請求頭信息不超出以下幾種字段
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三個值application/x-www-form-urlencoded、multipart/form-data、text/plain
非簡單請求(not-so-simple request),不滿足以上兩個條件的請求就是非簡單請求
AJAX發起跨域請求時,如果是簡單類型請求,請求頭信息如下:
GET /cors HTTP/1.1
Origin: http://api.bob.com //發起此次請求的所在源(協議+域名+端口號)
Host: api.alice.com //要訪問的目標域
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
如果Origin指定的源,不在服務端許可范圍內,服務器會返回一個正常的HTTP回應。但這個響應頭信息沒有包含Access-Control-Allow-Origin字段。瀏覽器接收后就知道出錯了,從而拋出一個錯誤,被XMLHttpRequest的onerror回調函數捕獲。這種錯誤無法通過狀態碼識別,因為HTTP回應的狀態碼有可能是200。
如果Origin指定的域名在許可范圍內,服務器返回的響應,響應頭會包含以下信息字段
Access-Control-Allow-Origin: http://api.bob.com //允許來自源http://api.bob.com的訪問,如果是*則代表允許來自所有源的訪問
Access-Control-Allow-Credentials: true //是否允許客戶端在請求中發送Cookie
Access-Control-Expose-Headers: FooBar //允許CORS請求拿到除默認的Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma外的其他字段。這里允許拿到foobar字段信息。
Content-Type: text/html; charset=utf-8
CORS請求默認不包含Cookie信息,如果需要包含Cookie信息,一方面要服務器同意
Access-Control-Allow-Credentials: true //但Access-Control-Allow-origin 不能是*
另一方面,開發者必須在AJAX請求中打開withCredentials屬性。
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
此時Cookie依然遵循同源政策,只有用服務器域名設置的Cookie才會上傳,其他域名的Cookie并不會上傳,且(跨源)原網頁代碼中的document.cookie也無法讀取服務器域名下的Cookie。
AJAX發起跨域請求時,如果是非簡單類型請求,比如請求方法是PUT或DELETE,或者Content-Type字段的類型是application/json,非簡單請求的CORS請求,會在正式通信之前,增加一次HTTP查詢請求,稱為“預檢”請求,瀏覽器先詢問服務器,當前網頁所在的域名是否在服務器的許可名單之中,以及可以使用哪些HTTP動詞和頭信息字段。只有得到肯定答復,瀏覽器才會發出正式的XMLHttpRequest請求,否則就報錯。
比如js代碼如下:
var url = "http://api.alice.com/cors";
var xhr = new XMLHttpRequest();
xhr.open("PUT", url, true); //方法是PUT
xhr.setRequestHeader("X-Custom-Header", "value"); //自定義請求頭信息
xhr.send();
請求頭信息如下:
OPTIONS /cors HTTP/1.1 //方法是OPTIONS,表示這個請求是用來詢問的。
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
如果服務器否定了“預檢”請求,會返回一個正常的HTTP回應,但是沒有任何CORS相關的頭信息字段。瀏覽器接收后就知道出錯了,被XMLHttpRequest對象的onerror回調函數捕獲。
如果服務器接受了“預檢”請求,以后每次瀏覽器正常的CORS請求,就都跟簡單請求一樣,會有一個Origin頭信息字段。服務器的回應,也都會有一個Access-Control-Allow-Origin頭信息字段。服務器發送響應頭信息如下:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT //表明服務器支持的所有跨域請求的方法
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
JSONP只支持GET請求,CORS支持所有類型的HTTP請求。JSONP的優勢在于支持老式瀏覽器,以及可以向不支持CORS的網站請求數據。
3.HTML5跨文檔通信API window.postMessageHTML5中最酷的新功能之一就是 跨文檔消息傳輸Cross Document Messaging。下一代瀏覽器都將支持這個功能:Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 。 Facebook已經使用了這個功能,用postMessage支持基于web的實時消息傳遞。
舉例,父窗口aaa.com向子窗口bbb.com發消息,調用postMessage方法如下:
var popup = window.open("http://bbb.com", "title"); popup.postMessage("Hello World!", "http://bbb.com");
postMessage方法的第一個參數是具體的信息內容(支持任意類型),第二個參數是接收消息目標窗口的源origin(協議 + 域名 + 端口)也可以設為*,表示不限制域名,向所有窗口發送。
子窗口向父窗口發送消息的寫法如下:
window.opener.postMessage("Nice to see you", "http://aaa.com");
父窗口和子窗口都可以通過message事件,監聽對方的消息:
window.addEventListener("message", function(event) { console.log(e.data); },false);
事件對象event的三個屬性:
event.source:發送消息的窗口對象,對發送消息的窗口對象的引用;
event.origin: 發送消息的窗口的源(協議、域名、端口號)這里不是接受消息的窗口的源
event.data: 消息內容
event.origin屬性可以過濾不是發給本窗口的消息,舉例如下:
當bbb網站收到來自aaa網站發來的消息
window.addEventListener("message", receiveMessage); function receiveMessage(event) { if (event.origin !== "http://aaa.com") return;//判斷發消息的窗口的源是否是aaa網站的源,這里的event.origin和postMessage()方法中的origin不一樣!! if (event.data === "Hello World") { event.source.postMessage("Hello", event.origin);//這里event.origin指向aaa網站的源即消息接收的窗口的源 } else { console.log(event.data); } }
otherWindow.postMessage方法中,otherWindow是其他窗口的一個引用,比如iframe的contentWindow屬性、執行window.open返回的窗口對象、或者是命名過或數值索引的window.frames。即只能適用于open方法打開的頁面相互發送消息,或者通過iframe嵌套的頁面之間發送消息。通過window.postMessage()方法還可讀取其他窗口的LocalStorage
window.open("http://www.bbb.com:8881/b_index.html","title") //主頁面中打開子頁面
window.opener.postMessage(${msg},"http://www.aaa.com:8888") //引用打開子頁面的主頁面
當兩個網頁一級域名相同,只是二級域名不同,瀏覽器允許通過設置document.domain來實現iframe窗口相互訪問或設置cookie。降域方式只適用于同一站點下不同子域名共享cookie或者iframe頁面中嵌套的子域名頁面之間的訪問。降域不適用訪問LocalStorage 和 IndexedDB,postMessage()方法可訪問LocalStorage
用改寫document.domain+iframe的方法來獲取目標域數據。缺點是安全性差,一個頁面被攻擊后另一個頁面的數據也會被泄露且不支持ajax方式請求數據。降域只能解決主域相同而二級域名(子域名)不同的兩個頁面請求數據的情況,如果把script.a.com的domian設為alibaba.com那顯然是會報錯。domain只能設置為主域名,不可以在b.a.com中將domain設置為c.a.com;且只能由子域名改到父域名或父父域名,不能從父父域名改到子域名(比如將b.com改成script.b.com是不行的)
舉例來說,A網頁是http://w1.example.com/a.html,B網頁是http://w2.example.com/b.html,子域名不同默認情況下會被同源策略阻止訪問。只要將兩個頁面都設置相同的document.domain,兩個網頁就可以共享Cookie或在iframe窗口下相互訪問。
document.domain = "example.com";
服務器也可以在設置 Cookie 的時候,指定 Cookie 的所屬域名為一級域名以后二級域名和三級域名不用做任何設置,都可以讀取這個Cookie。比如.example.com。
Set-Cookie: key=value; domain=.example.com; path=/
降域的特點:只能對主域相同子域不同的iframe頁面和父頁面(或者open方法打開的主域相同的頁面)形式的跨域起作用,可實現的兩個頁面共享cookie。修改domain時top頁面和iframe頁面都要使用document.domain去修改成一致的域名。具體的做法是可以在http://www.a.com/a.html和http://script.a.com/b.html兩個文件中分別加上document.domain = "a.com";然后通過a.html文件中創建一個iframe,去控制iframe的contentDocument,這樣兩個js文件之間就可以“交互”了。驗證步驟如下:
1.本地文件夾中有兩個文件index.html(www.a.com下的網頁),b.html(script.a.com下的網頁),a.com下的index.html頁面中有iframe頁面(src="http://script.a.com:8080/b.html")
2.由于域僅僅是通過“URL的首部”來識別,不會判斷兩個不同域名是否為同一IP地址。根據這點,修改本地host文件增加兩行,子域名不同,主域名相同來模擬跨域。
127.0.0.1 www.a.com
127.0.0.1 script.a.com
3.用mock start命令啟動服務器并分別訪問
http://www.a.com:8080/index.html
http://script.a.com:8080/b.html
兩個頁面console.log(document.domain)時分別返回www.a.com和script.a.com,此時是跨域狀態。
4.當在www.a.com下的html頁面中執行以下腳本時提示
var ccc=document.getElementsByTagName("iframe")[0].contentDocument
(注:.contentDocument方法可操作iframe頁面內的信息)
5.解決方案:www.a.com下的index.html頁面和script.a.com下的b.html頁面中都增加腳本,將兩個頁面的域設置成相同的主域名
再次執行var ccc=document.getElementsByTagName("iframe")[0].contentDocument
返回的就是b.html文件中的信息
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/108121.html
摘要:可以說同源策略在安全中扮演著及其重要的角色。我把這個領域的東西寫成了一個系列,以后還會繼續完善下去安全一同源策略與跨域安全二攻擊安全三攻擊 之所以要將同源策略與跨域寫在一起,是因為存在瀏覽器的同源策略,才會存在跨域問題 何為同源策略 同源策略是瀏覽器實現的一種安全策略,它限制了不同源之間的文檔和腳本交互的權限。只有同一個源的腳本才會具有操作dom、讀寫cookie、session 、a...
摘要:由于瀏覽器的同源策略導致無法直接通過拿到后臺數據。目前,如果非同源,共有三種行為受到限制。此處應有掌聲參考關于跨域資源共享和瀏覽器的同源策略限制的具體講解。 工作中,經常會遇到需要跨域請求數據的情況。由于瀏覽器的同源策略,導致無法直接通過ajax拿到后臺數據。解決這個問題的方式之一就是JSONP。還有一種方式更高效簡單——跨域資源共享(Cross-origin Resource Sha...
摘要:扯了這么多,自然不是為了吹水,而是要為了引出前端開發的一個重要的知識點同源策略什么是同源策略出于保護用戶信息安全的目的,現在的瀏覽器都會實施同源策略這個政策,所謂同源策略指的是不同源的客戶端腳本在沒有明確授權情況下,不允許讀寫對方的資源。 導語你家的小孩帶了他的朋友來你們的家里玩,你家的小孩如果要在自家屋里拿玩具玩、拿東西吃你自然是不會阻止,但是如果你家小孩的朋友人品不行,亂拿東西吃、...
摘要:扯了這么多,自然不是為了吹水,而是要為了引出前端開發的一個重要的知識點同源策略什么是同源策略出于保護用戶信息安全的目的,現在的瀏覽器都會實施同源策略這個政策,所謂同源策略指的是不同源的客戶端腳本在沒有明確授權情況下,不允許讀寫對方的資源。 導語你家的小孩帶了他的朋友來你們的家里玩,你家的小孩如果要在自家屋里拿玩具玩、拿東西吃你自然是不會阻止,但是如果你家小孩的朋友人品不行,亂拿東西吃、...
摘要:方案瀏覽器設置一級域名。場景完全不同源的網站,需要窗口通信方案父子窗口互相寫互相監聽子窗口寫后跳回同域父窗口讀瀏覽器跨文檔通信場景請求非同源地址方案架設服務器代理參考資料瀏覽器同源政策及其規避方法阮一峰前端常見跨域解決方案全跨域幾種方式 同源 概念:協議,域名,端口 相同。目的:保證用戶信息的安全,防止惡意的網站竊取數據。限制的行為: Cookie、LocalStorage 和 In...
摘要:方案瀏覽器設置一級域名。場景完全不同源的網站,需要窗口通信方案父子窗口互相寫互相監聽子窗口寫后跳回同域父窗口讀瀏覽器跨文檔通信場景請求非同源地址方案架設服務器代理參考資料瀏覽器同源政策及其規避方法阮一峰前端常見跨域解決方案全跨域幾種方式 同源 概念:協議,域名,端口 相同。目的:保證用戶信息的安全,防止惡意的網站竊取數據。限制的行為: Cookie、LocalStorage 和 In...
閱讀 2058·2021-11-11 16:54
閱讀 1038·2021-10-12 10:12
閱讀 376·2019-08-30 15:43
閱讀 645·2019-08-29 13:15
閱讀 1074·2019-08-29 13:12
閱讀 1524·2019-08-26 12:09
閱讀 1654·2019-08-26 10:24
閱讀 2250·2019-08-26 10:15