跨域的那些事兒
前言
最近做專案的時候遇到了一些跨域問題,雖然網上對於跨域的問題分享還挺多的。不過當我實際遇到的時候還是有點懵。趁專案剛上線完,寫篇文章總結下。
造成跨域的兩種策略
瀏覽器的同源策略會導致跨域,這裡同源策略又分為以下兩種
DOM同源策略:禁止對不同源頁面DOM進行操作。這裡主要場景是iframe跨域的情況,不同域名的iframe是限制互相訪問的。
XmlHttpRequest同源策略:禁止使用XHR物件向不同源的伺服器地址發起HTTP請求。
只要協議、域名、埠有任何一個不同,都被當作是不同的域,之間的請求就是跨域操作。
為什麼要有跨域限制
瞭解完跨域之後,想必大家都會有這麼一個思考,為什麼要有跨域的限制,瀏覽器這麼做是出於何種原因呢。其實仔細想一想就會明白,跨域限制主要是為了安全考慮。
AJAX同源策略主要用來防止CSRF攻擊。如果沒有AJAX同源策略,相當危險,我們發起的每一次HTTP請求都會帶上請求地址對應的cookie,那麼可以做如下攻擊:
使用者登入了自己的銀行頁面
http://
mybank。com
,
http://
mybank。com
向用戶的cookie中新增使用者標識。
使用者瀏覽了惡意頁面
http://
evil。com
。執行了頁面中的惡意AJAX請求程式碼。
http://
evil。com
向
http://
mybank。com
發起AJAX HTTP請求,請求會預設把
http://
mybank。com
對應cookie也同時傳送過去。
銀行頁面從傳送的cookie中提取使用者標識,驗證使用者無誤,response中返回請求資料。此時資料就洩露了。
而且由於Ajax在後臺執行,使用者無法感知這一過程。
DOM同源策略也一樣,如果iframe之間可以跨域訪問,可以這樣攻擊:
做一個假網站,裡面用iframe巢狀一個銀行網站
http://
mybank。com
。
把iframe寬高啥的調整到頁面全部,這樣使用者進來除了域名,別的部分和銀行的網站沒有任何差別。
這時如果使用者輸入賬號密碼,我們的主網站可以跨域訪問到
http://
mybank。com
的dom節點,就可以拿到使用者的輸入了,那麼就完成了一次攻擊。
所以說有了跨域跨域限制之後,我們才能更安全的上網了。
跨域的解決方式
> 跨域資源共享
CORS是一個W3C標準,全稱是”跨域資源共享”(Cross-origin resource sharing)。 對於這個方式,阮一峰老師總結的文章特別好,希望深入瞭解的可以看一下
http://www。
ruanyifeng。com/blog/201
6/04/cors。html
。
這裡我就簡單的說一說大體流程。
對於客戶端,我們還是正常使用xhr物件傳送ajax請求。
唯一需要注意的是,我們需要設定我們的xhr屬性withCredentials為true,不然的話,cookie是帶不過去的哦,設定: xhr。withCredentials = true;
對於伺服器端,需要在 response header中設定如下兩個欄位:
Access-Control-Allow-Origin:
http://www。
yourhost。com
Access-Control-Allow-Credentials:true
這樣,我們就可以跨域請求介面了。
> jsonp實現跨域
基本原理就是透過動態建立script標籤,然後利用src屬性進行跨域。
這麼說比較模糊,我們來看個例子:
// 定義一個fun函式
function
fun
(
fata
)
{
console
。
log
(
data
);
};
// 建立一個指令碼,並且告訴後端回撥函式名叫fun
var
body
=
document
。
getElementsByTagName
(
‘body’
)[
0
];
var
script
=
document
。
gerElement
(
‘script’
);
script
。
type
=
‘text/javasctipt’
;
script
。
src
=
‘demo。js?callback=fun’
;
body
。
appendChild
(
script
);
返回的js指令碼,直接會執行。所以就執行了事先定義好的fun函數了,並且把資料傳入了進來。
fun
({
“name”
:
“name”
})
當然,這個只是一個原理演示,實際情況下,我們需要動態建立這個fun函式,並且在資料返回的時候銷燬它。
因為在實際使用的時候,我們用的各種ajax庫,基本都包含了jsonp的封裝,不過我們還是要知道一下原理,不然就不知道為什麼jsonp不能發post請求了~
> 伺服器代理
瀏覽器有跨域限制,但是伺服器不存在跨域問題,所以可以由伺服器請求所要域的資源再返回給客戶端。
伺服器代理是萬能的。
> document.domain來跨子域
對於主域名相同,而子域名不同的情況,可以使用document。domain來跨域 這種方式非常適用於iframe跨域的情況,直接看例子吧 比如a頁面地址為
http://
a。yourhost。com
b頁面為
http://
b。yourhost。com
。 這樣就可以透過分別給兩個頁面設定 document。domain =
http://
yourhost。com
來實現跨域。 之後,就可以透過 parent 或者 window[‘iframename’]等方式去拿到iframe的window物件了。
使用window。name進行跨域
window。name跨域同樣是受到同源策略限制,父框架和子框架的src必須指向統一域名。window。name的優勢在於,name的值在不同的頁面(或者不同的域名),載入後仍然存在,除非你顯示的更改。並且支援的長度達到2M。
//a頁面的程式碼
<
script
type
=
“text/javascript”
>
iframe
=
document
。
createElement
(
‘iframe’
);
iframe
。
style
。
display
=
‘none’
;
var
state
=
0
;
iframe
。
onload
=
function
()
{
if
(
state
===
1
)
{
var
data
=
iframe
。
contentWindow
。
name
;
console
。
log
(
data
);
iframe
。
contentWindow
。
document
。
write
(
‘’
);
iframe
。
contentWindow
。
close
();
document
。
body
。
removeChild
(
iframe
);
}
else
if
(
state
===
0
)
{
state
=
1
;
iframe
。
contentWindow
。
location
=
‘http://m。zhuanzhuan。58。com:8887/b。html’
;
}
};
document
。
body
。
appendChild
(
iframe
);
<
/script>
//b頁面程式碼
<
script
type
=
“text/javascript”
>
window
。
name
=
“hello”
;
<
/script>
> location.hash跨域
location。hash方式跨域,是子框架具有修改父框架src的hash值,透過這個屬性進行傳遞資料,且更改hash值,頁面不會重新整理。但是傳遞的資料的位元組數是有限的。
//a頁面的程式碼
<
script
type
=
“text/javascript”
>
iframe
=
document
。
createElement
(
‘iframe’
);
iframe
。
style
。
display
=
‘none’
;
var
state
=
0
;
iframe
。
onload
=
function
()
{
if
(
state
===
1
)
{
var
data
=
window
。
location
。
hash
;
console
。
log
(
data
);
iframe
。
contentWindow
。
document
。
write
(
‘’
);
iframe
。
contentWindow
。
close
();
document
。
body
。
removeChild
(
iframe
);
}
else
if
(
state
===
0
)
{
state
=
1
;
iframe
。
contentWindow
。
location
=
‘http://m。zhuanzhuan。58。com:8887/b。html’
;
}
};
document
。
body
。
appendChild
(
iframe
);
<
/script>
//b頁面程式碼
<
script
type
=
“text/javascript”
>
parent
。
location
。
hash
=
“world”
;
<
/script>
> 使用postMessage實現頁面之間通訊
資訊傳遞除了客戶端與伺服器之前的傳遞,還存在以下幾個問題:
頁面和新開的視窗的資料互動。
多視窗之間的資料互動。
頁面與所巢狀的iframe之間的資訊傳遞。
window。postMessage是一個HTML5的api,允許兩個視窗之間進行跨域傳送訊息。這個應該就是以後解決dom跨域通用方法了,具體可以參照MDN。
補充: 其實還有一些方法,比如window。name和location。hash。就很適用於iframe的跨域,不過iframe用的比較少了,所以這些方法也就有點過時了。
這些就是我對跨域的瞭解了,實際情況下,一般用cors,jsonp等常見方法就可以了。不過遇到了一些非常規情況,我們還是需要知道有更多的方法可以選擇的
以上便是這次的文章分享了,可以給作者留言相互學習。也可以關注他的個人部落格
https://
wangningbo93。github。io/
。
上一篇:減肥方法哈哈哈哈
下一篇:Loro Piana到底好在哪?