您當前的位置:首頁 > 舞蹈

跨域的那些事兒

作者:由 大轉轉FE 發表于 舞蹈時間:2017-08-16

前言

最近做專案的時候遇到了一些跨域問題,雖然網上對於跨域的問題分享還挺多的。不過當我實際遇到的時候還是有點懵。趁專案剛上線完,寫篇文章總結下。

造成跨域的兩種策略

瀏覽器的同源策略會導致跨域,這裡同源策略又分為以下兩種

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/

標簽: 跨域  iframe  http  頁面  com