咱們以前提到過,AJAX技術使開發者可以專一於互聯網中數據的傳輸,而再也不拘泥於數據傳輸的載體。經過AJAX技術,咱們獲取數據的方式變得更加靈活,可控和優雅。數據庫
可是AJAX技術並非一把萬能鑰匙,互聯網中的數據隱私和數據安全(例如你的銀行帳號和密碼)也很是重要,爲了保護某些用戶數據的隱私與安全,瀏覽器使用「同源策略」限制了AJAX技術獲取數據的範圍和能力。但在一些合理的場景中,咱們又不得不想辦法繞過同源策略,實現跨域請求資源。所以「跨域技術」一直成爲開發者們經久不衰的討論話題。segmentfault
在「跨域獲取資源」這一主題中,咱們將圍繞「同源策略」和「跨域」兩大主題展開,不但講述它們是什麼,更說明了爲何要這麼作。相信你在讀完該主題下的兩篇文章後,必定會對這兩大主題有一個清晰,系統的認識。跨域
須要提早聲明的是,本主題下的文章並不會像衆多相同主題的文章同樣羅列出全部的跨域技術,而只會撿最主流的四種進行講解。由於我並不打算寫「教你如何跨域」這樣類型的文章。瀏覽器
讓咱們開始吧。安全
整個互聯網世界的數據要麼存儲在服務端(即服務器,如數據庫,硬盤等)中,要麼存儲在客戶端(即瀏覽器,如cookie,LocalStorage,sessionStorage)中。互聯網數據的傳輸實際上就是客戶端與服務端之間的交互。服務器
而所謂的數據隱私與安全保護,說白了就是數據擁有者對數據索取者發出警告:「不是你的你別動」。cookie
搞清了這個原則,咱們就很容易明白,若是你在客戶端,而且想要獲取服務端數據,你首先須要經過服務器端的驗證,證實你有權限獲取數據(例如「登陸」),而若是你在服務端,想要獲取客戶端的某些數據,你一樣須要客戶端經過某些方式驗證你有資格獲取相應的數據資源。session
那麼上面提到的「某些方式」是什麼呢?其中最重要的就是咱們今天的主題之一 -- 瀏覽器的「同源策略」。dom
瀏覽器所遵照的「同源策略」是指:限制不一樣源之間執行特定操做。這涉及到兩個問題:什麼是「源」?,以及「特定操做」是指什麼?網站
讓咱們停下來解釋一下這個概念:
在搞清了同源策略的概念以後,讓咱們看看瀏覽器是出於怎樣的考慮,一直堅守着同源策略:
由於不一樣的源,大多數狀況下就意味着它們在互聯網中歸屬於不一樣的站點(或是被用做不一樣的用途)。也就是說它們是不一樣的項目,有不一樣的文件根目錄,那麼它們的數據也不該該共享也就理所應當了,不然數據的隱私和安全也無從談起。不過請注意,我上面所說的話是基於「不一樣源就彼此不相干」的假設,這其實存在一些問題,咱們以後會提到。
這個須要咱們假設,若是咱們想作一些「壞事」,而且瀏覽器容許咱們執行這些「特定操做」,咱們做爲「壞人」能作什麼:
首先,因爲不少網站使用瀏覽器存儲用戶的用戶名和密碼,那麼咱們即可以在A域中(咱們在服務器上託管的網站)讀取任意來訪用戶的全部Cookie信息(沒有同源策略的保護,該用戶全部網站的Cookie記錄都是透明的),咱們就能夠利用這些Cookie信息假裝成來訪用戶作任何事,而在現實世界,出於同源政策的保護,咱們只能訪問用戶該域下的Cookie信息,也就是說,咱們只能訪問咱們本身設置的Cookie信息。
其次,若是咱們可以獲取不一樣域下的DOM元素,咱們就能夠經過<iframe>
標籤在咱們的A域網站上引入B域網站,而後誘使用戶在B域網站操做,因爲咱們可以跨域獲取DOM元素,所以咱們能夠操做B域網站的DOM結構,用戶輸入的一切信息,以及用戶操做的DOM元素就都在咱們的掌控之中了。這正是同源策略想要規避的安全隱患。
最後,爲何要禁止不一樣源的站點發送AJAX請求呢?這個提及來有些複雜,咱們首先要對Cookie的運做原理有一個大體的瞭解:
當咱們設置Cookie時,除了存放鍵值對形式的數據信息外,瀏覽器還會爲Cookie的一些屬性填充默認值(咱們也能夠手動修改這些屬性的值)。在這些屬性中,咱們須要關注domain
和path
兩個屬性,它們一個表明域名,一個表明路徑,二者加起來構成了一個肯定這條Cookie什麼時候被調用和訪問的URL。與此同時,瀏覽器本身維護的Cookie文件中也會添加這一條新建立的Cookie數據。
當咱們在瀏覽器中發送HTTP請求時,瀏覽器首先會檢查請求地址並在本身所維護的Cookie文件中尋找匹配的Cookie信息,將其添加到請求頭中的Cookie
屬性內,而後向服務器發送請求。請注意,這個自動添加相應Cookie信息的過程是瀏覽器本身偷偷幫咱們作到的,也就是說,咱們本身沒法控制這個過程。
下面重點來了,當咱們的HTTP請求到達服務器時,服務器返回的響應中,響應頭會原封不動的返回咱們發送給他的Cookie信息。嗅到危險的味道了嗎?咱們雖然不能在發送請求前得到Cookie信息,可是在發送請求後,咱們仍是可以得到用戶的Cookie!
讓我再進一步解釋一下這和AJAX有什麼關係,假設咱們在本身的服務器上託管了站點A,並在其中隱藏了一段腳本,每一個登陸站點A的人都會自動發送AJAX請求至站點B(提示:站點B是一個銀行),那麼在沒有瀏覽器同源策略的狀況下,若是站點A中的訪問者剛好有Cookie中保留站點B信息的用戶,經過AJAX請求返回的響應頭,咱們同樣能夠拿到這位用戶的站點B Cookie,從而假裝成用戶在站點B登陸,作一些違法亂紀的事情(CSRF攻擊便是利用了這個原理,只不過出於同源策略限制,並不能經過發起AJAX的方式)。
雖然有些費勁,可是如今你應該明白爲何同源策略要阻止跨域發送AJAX了吧?(我終於將這個概念說清楚了,真是費了很多力氣 👻)
想要了解更多關於Cookie的信息,能夠參考這篇文章
看看咱們的任務清單,咱們解釋了什麼是同源策略以及瀏覽器爲何要有同源策略,但至今爲止,咱們還未曾看到,在瀏覽器同源策略的限制下,當咱們想要獲取跨域Cookie,DOM結構和發送AJAX時,咱們是如何被「拒絕」的。
首先,咱們在一個域下只能讀取該域下的Cookie值。當咱們在頁面中使用<iframe>
標籤時,咱們獲取對應DOM節點下只有一個空空的#document
節點,並無額外的DOM信息。
而對於AJAX,瀏覽器其實並無阻止咱們向不一樣域發送請求,其阻止的是此次請求的響應,也就是說服務端其實接收到了此次請求,只是響應被瀏覽器解析時被瀏覽器發現違背了同源策略而被拒絕,此時,瀏覽器會在控制檯中打印出一條錯誤信息。
另外須要注意的是,對於XHR請求,實際上咱們在請求報頭也不會看到相應的Cookie信息,這是由於CORS標準中作了規定,默認狀況下,瀏覽器在發送跨域請求時,不能發送任何認證信息,好比cookies
和HTTP authentication schemes
。除非你顯式的將xhr
實例的withCredentials
屬性的值設置爲true
而且服務器端也容許客戶端請求攜帶認證信息(即服務器端在響應頭中設置了Access-Control-Allow-Credentials: true
)。
要在跨域請求頭中顯示Cookie真是不容易對吧?
可是,等等!CORS標準是什麼?
問得好,在下一篇以「跨域發送請求」爲主題的文章中,咱們會詳細談到他。目前爲止,你已經充分了解「同源策略」這個主題。Good Job!
如今讓咱們先暫時休息一下,下一篇見 🙌。