成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

同源策略和跨域

ideaa / 3206人閱讀

摘要:一些技術(shù)都默認(rèn)采取了同源策略,這些技術(shù)范圍包括但不限于。但是相比較以上的各種場景和繞過同源策略的方法,的跨域請求設(shè)置很容易,只需要在目標(biāo)服務(wù)的根目錄下

在前端開發(fā)的過程中,我們經(jīng)常遇到"跨域"的問題,以下的文章將列舉一下我在工作中碰到的跨域問題。
以及稍稍的探討一下為什么會有"跨域"問題的出現(xiàn),和所謂的"同源策略"

同源策略 1. 歷史

1995 年由 Netscape 公司提出,之后被其他瀏覽器廠商采納。

同源策略只是一個規(guī)范,并沒有指定其具體的使用范圍和實現(xiàn)方式,各個瀏覽器廠商都針對同源策略做了自己的實現(xiàn)。

一些 web 技術(shù)都默認(rèn)采取了同源策略,這些技術(shù)范圍包括但不限于Silverlight, Adobe Flash, Adobe Acrobat, Dom, XMLHttpRequest。

2. 定義
Under the policy, a web browser permits scripts contained in a first web page to access data in a second web page, but only if both web pages have the same origin. An origin is defined as a combination of URI scheme, hostname, and port number.

判斷同源的三個要素:

相同的協(xié)議

相同的域名

相同的端口號

3. 存在的意義
為了保證使用者信息的安全,防止惡意網(wǎng)站篡改用戶數(shù)據(jù)

舉個例子:

假設(shè)沒有同源策略,那么我在A網(wǎng)站下的cookie就可以被任何一個網(wǎng)站拿到;那么這個網(wǎng)站的所有者,就可以使用我的cookie(也就是我的身份)在A網(wǎng)站下進(jìn)行操作。

同源策略可以算是 web 前端安全的基石,如果缺少同源策略,瀏覽器也就沒有了安全性可言。

4. 限制范圍

非同源的網(wǎng)站之間

無法共享 cookie, localStorage, indexDB

無法操作彼此的 dom 元素

無法發(fā)送 ajax 請求

無法通過 flash 發(fā)送 http 請求

其他

跨域

同源策略做了很嚴(yán)格的限制,但是在實際的場景中,又確實有很多地方需要突破同源策略的限制,也就是我們常說的跨域

1. cookie

同源策略最早被提出的時候,為的就是防止不同域名的網(wǎng)頁之間共享 cookie,但是如果兩個網(wǎng)頁的一級域名是相同的,可以通過設(shè)置 document.domain來共享 cookie。

舉個例子,
https://market.douban.comhttps://book.douban.com,這兩個網(wǎng)頁的一級域名都是 douban.com,如果我在 market.douban.com中執(zhí)行了

    document.domain = "douban.com"
    document.cookie = "cross=yes"
    或
    document.cookie = "cross=yes;path=/;domain=douban.com"

這樣設(shè)置了 cookie 之后,在 book.douban.com 中是可以取到這個 cookie 的。

除了在前端設(shè)置之外,也可以直接在 response 里將 cookie 的 domain 設(shè)置成 .douban.com。

2. Ajax

在使用 ajax 的過程中,我們碰到的同源限制的問題是最多的。

針對 ajax ,我們有三種方式可以繞過同源策略的限制:

2.1 設(shè)置 CORS

設(shè)置 cross-domain 是目前在 ajax 中最常用的一種跨域的方式,相比jsonpwebsoket也是最安全的一種方式。

唯一美中不足的是低版本的瀏覽器支持的不是很好

IE ? 5.5+ ? 8+2 ? 10+1 ? 11

Edge ?

Firefox ? 2+ ? 3.5+

Chrome ? 4+1 ? 13+

Safari ? 3.1+ ? 4+1 ? 6+3

Opera ? 9+ ? 12+

1Does not support CORS for images in

2Supported somewhat in IE8 and IE9 using the XDomainRequest object (but has limitations)

3Does not support CORS for in : https://bugs.webkit.org/show_...

2.1.1 CORS 的運作

CROS 的設(shè)置,大部分是需要在服務(wù)端進(jìn)行設(shè)置,在服務(wù)端設(shè)置之前,先來看一下 CROS 在瀏覽器中是怎么運作的:

首先,在瀏覽器中,http 請求將被分為兩種 簡單請求(simple request)非簡單請求(not-so-simple request)。

簡單請求的判斷包括兩個條件:

請求方法必須是一下幾種:

HEAD

GET

POST

HTTP 頭只能包括以下信息:

Accept

Accept-Language

Content-Language

Last-Event-ID

Content-Type: 只限于[application/x-www-form-urlencoded, multipart/form-data, text/plain]

不能同時滿足以上兩個條件的,就都視作非簡單請求

2.1.2 簡單請求(simple request)
瀏覽器端

瀏覽器在處理簡單請求時,會在 Header 中加上一個 origin(protocal + host + path + port) 字段,來標(biāo)明這個請求是來自哪里。

在 CROS 請求中,默認(rèn)是不會攜帶 cookie之類的用戶信息的,但是不攜帶用戶信息的話,是沒辦法判斷用戶身份的,所以,可以在請求時將withCredentials設(shè)置為 true, 例如:

    var xhr = new XMLHttpRequest()
    xhr.withCredentials = true

設(shè)置了這個值之后,在服務(wù)端會將 response 中的 Access-Control-Allow-Credentials 也設(shè)置為 true,這樣瀏覽器才會相應(yīng) cookie

服務(wù)端

在服務(wù)端拿到這個請求之后,會對 origin 進(jìn)行判斷,如果是在允許范圍內(nèi)的請求,將會在 respones 返回的 Header 中加上:

    Access-Control-Allow-Origin: origin
    Access-Control-Allow-Credentials: true
    Access-Control-Expose-Headers: something

下面來說說這幾個字段都代表什么:

Access-Control-Allow-Origin

看名字大概就能猜出來,這個就是告訴瀏覽器,服務(wù)端接受那些域名的訪問。值可以是 request 中的 origin,也可以是 *,也可以是originA | originB 這樣的形式,但是目前看來,在瀏覽器中只支持單一值和*兩種方式。具體可以參考這里:access-control-allow-origin-response-header

Access-Control-Allow-Credentials

從名字上來看,這個字段標(biāo)明了是否擁有用戶相關(guān)的權(quán)限。

在瀏覽器中,具體表現(xiàn)為是否可以發(fā)送 cookie。這個值可以選擇性返回,如果不返回的話,默認(rèn)就 是不允許發(fā)送 cookie,如果返回,則只能返回 true。

另外,如果這個值被設(shè)為了true,那么Access-Control-Allow-Origin就不能被設(shè)置為 *,必須要顯示指定為origin的值;并且返回的cookie因為是在被跨域訪問的域名下,因為遵守同 源策略,所以在origin網(wǎng)頁中是不能被讀取到的。

Access-Control-Expose-Headers

從字面意義上來看,這個字段返回的就是其他可被返回的數(shù)據(jù)。

之所以會有這個字段,是因為在簡單請求中,response返回的頭信息中,瀏覽器只能拿到以下幾個基本字段:Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma

如果想要拿到更多的額外信息,只能在Access-Control-Expose-Headers里設(shè)置,例如:

     Access-Control-Expose-Headers: "Foo=foo"

這樣的話,在瀏覽中,就可以獲取 Foo 這個字段所攜帶的信息了

2.1.3 非簡單請求(not-so-simple request)

簡單請求最大的不同在于,非簡單請求實際上是發(fā)送了兩個請求。

預(yù)請求

首先,在正式請求之前,會先發(fā)送一個預(yù)請求(preflight-request),這個請求的作用是盡可能少的攜帶信息,供服務(wù)端判斷是否響應(yīng)該請求。

瀏覽器

瀏覽器發(fā)送預(yù)請求,請求的 Request Method 會設(shè)置為 options。

另外,還會帶上這幾個字段:

Origin: 同簡單請求origin

Access-Control-Request-Method: 請求將要使用的方法

Access-Control-Request-Headers: 瀏覽器會額外發(fā)送哪些頭信息

服務(wù)端

服務(wù)端收到預(yù)請求之后會根據(jù)request中的origin,Access-Control-Request-MethodAccess-Control-Request-Headers判斷是否響應(yīng)該請求。

如果判斷響應(yīng)這個請求,返回的response中將會攜帶:

Access-Control-Allow-Origin: origin

Access-Control-Allow-Methods: like request

Access-Control-Allow-Headers: like request

如果否定這個請求,直接返回不帶這三個字段的response就可以,瀏覽器將會把這種返回判斷為失敗的返回,觸發(fā)onerror方法

正式響應(yīng)

如果預(yù)請求被正確響應(yīng),接下來就會發(fā)送正式請求,正式請求的request和正常的 ajax 請求基本沒有區(qū)別,只是會攜帶 origin 字段;response簡單請求一樣,會攜帶上Access-Control-*這些字段

2.2 websocket

websocket 不遵循同源策略。

但是在 websocket 請求頭中會帶上 origin 這個字段,服務(wù)端可以通過這個字段來判斷是否需要響應(yīng),在瀏覽器端并沒有做任何限制。

2.3 jsonp

jsonp 其實算是一種 hack 形式的請求。

jsonp 的本質(zhì)其實是請求一段 js 代碼,是對靜態(tài)文件資源的請求,所以并不遵循同源策略。但是因為是對靜態(tài)文件資源的請求,所以只能支持 GET 請求,對于其他方法沒有辦法支持。

3. iframe 3.1 iframe 中的同源策略

根據(jù)同源策略的規(guī)定,如果兩個頁面不同源,那么相互之間其實是隔離的。

在使用 iframe 的頁面中,雖然我們可以通過iframe.contentWindow,window.parent,window.top等方法拿到window對象,但是根據(jù)同源策略,瀏覽器將對非同源的頁面之間的windowlocation對象添加限制

不同源的兩個網(wǎng)頁將不能:

操作彼此的 dom

獲取/調(diào)用彼此 window 對象中的屬性/方法

不同源的兩個網(wǎng)頁可以:

改變父/子級的 url

具體的規(guī)則可以參考這里:integration-with-idl

但是在現(xiàn)實世界中,有很多場景下,其實是需要兩個非同源的 iframe 之間進(jìn)行“跨域”操作的。為了實現(xiàn)這種“跨域”,我們借用了以下幾種方法:

片段標(biāo)識符(fragment identifier)

使用 window.name

跨文檔通信

3.2 使用片段標(biāo)識符(fragment identifier)

片段標(biāo)識符指的就是 url 中 # 之后的部分,也就是我們常說的 location.hash。
使用片段標(biāo)識符依托于以下幾個關(guān)鍵點:

改變 url 里的這個部分,是不會觸發(fā)頁面的刷新的

父級頁面雖然不能操作 iframe 中的 windowdom,但是可以改變 iframe 的 url

window 對象可以監(jiān)聽 hashchange 事件

通過這幾個關(guān)鍵點,可以實現(xiàn)基于 hashchange 來操作頁面

3.3 使用 window.name

window.name這個屬性最厲害的地方在于,window對象沒有改變的話,這個 window 跳轉(zhuǎn)的網(wǎng)頁,都讀取 window.name 這個值。

例如,A 網(wǎng)頁設(shè)置了 window.name,然后跳轉(zhuǎn)到了 B 網(wǎng)頁,但是 B 網(wǎng)頁中,仍然可以讀取到 A 設(shè)置的 window.name

通過這個特性,在 iframe 中,子頁面可以先設(shè)置 window.name

然后跳轉(zhuǎn)到一個跟父頁面同級的地址,這個 window.name 依然存在,因為已經(jīng)調(diào)到了跟父級頁面同源的地址中,所以父頁面可以獲取到 iframe.contentWindow中屬性,也就是可以讀取到 window.name

這種方法最大的優(yōu)點就是window.name可以傳一個很長的字符串,但是缺點也比較明顯,就是需要在父級頁面不停的去檢查子頁面的window.name是否被改變

3.4 跨文檔通信API(Cross-document messaging)

雖然上面的兩種方法都可以實現(xiàn)不同源頁面之間的通信,但是總歸是屬于hack的方法,眼看著大家對非同源頁面的通信都有需求,所以在 HTML5 規(guī)范中,添加了一個window.postMessage的方法。

通過這個方法,可以方便的實現(xiàn)不同源的頁面之間的通信。

看一個簡單的例子:

// Page Foo
iframe.contentWindow.postMessage("Hello from foo", "/path/to/bar")


// Page Bar
window.parent.addEventListener("message", function (e) {
    console.log(e.source)    // 發(fā)送消息的窗口
    console.log(e.origin)  // 消息發(fā)向的網(wǎng)址
    console.log(e.data)    // 消息內(nèi)容
})
2.6 canvas

canvas 的使用過程中,也會碰到同源策略的限制。

以下的幾種操作,都會受到同源策略的限制:

canvas.toDataURL

canvas.toBlob

canvas.getContent("2d").getImageData(x,y,w,h)

例如:

// 這段 JS 運行在 a.com 這個域名下
var canvas = document.createElement("canvas")
var ctx = canvas.getContent("2d")
var src = "http://b.com/path/to/a/image"
var img = new Image()
img.onload = function () {
    canvas.with = img.style.width
    canvas.height = img.style.height
    ctx.drawImage(img)
    // 以下的這這三種操作都會報錯
    canvas.toDataURL("image/jpg")
    canvas.toBlob(function () {})
    ctx.getImageData(0, 0, 10, 10)
}
img.src = src

運行時會報錯

Uncaught SecurityError: Failed to execute "toDataURL" on "HTMLCanvasElement": Tainted canvases may not be exported.

可以看到是toDataURL的時候,因為 a.comb.com是不同源的兩個網(wǎng)頁,觸發(fā)了同源策略的限制。換成toBlobgetImageData會報同樣的錯誤。

我們來探究以下報這個錯誤的原因:

首先,所有bitmaps類型的對象,在被canvasImageBitmap使用時,都會先檢查當(dāng)前這對象,是不是處在origin clean的狀態(tài)。

然后,所有bitmaps類型的對象,默認(rèn)情況下,這個origin clean都是true,但是如果這個bitmaps被跨域調(diào)用,那么,這個origin clean將會被設(shè)置成 false。

再然后,在使用toDataURL,toBlobgetImageData時,都會先檢查origin clean,如果為 false 的話,就會拋出SecurityError這樣的異常。

那么,這個origin clean的狀態(tài),是如何設(shè)置的呢?

可以通過crossOrigin來設(shè)置,看代碼:

var canvas = document.createElement("canvas")
var ctx = canvas.getContent("2d")
var src = "http://b.com/path/to/a/image"
var img = new Image()
img.onload = function () {
    canvas.with = img.style.width
    canvas.height = img.style.height
    ctx.drawImage(img)
    canvas.toDataURL("image/jpg")
}
img.crossOrigin = "*"
img.src = src

加上了crossOrigin這個屬性,然后執(zhí)行,發(fā)現(xiàn)還會報個錯:

Image from origin "http://b.com" has been blocked from loading by Cross-Origin Resource Sharing policy: No "Access-Control-Allow-Origin" header is present on the requested resource. Origin "http://localhost:3000" is therefore not allowed access

看報錯信息大概可以知道,是Access-Control-Allow-Origin這里出了問題,只需要把Access-Control-Allow-Origin設(shè)置成對應(yīng)的值就可以了。

更具體的原因可以參考這里:Security with canvas elements

2.7 flash

flash在進(jìn)行 HTTP 請求時,也遵循同源策略。

但是相比較以上的各種場景和繞過同源策略的方法,flash 的跨域請求設(shè)置很容易,只需要在目標(biāo)服務(wù)的根目錄下設(shè)置一個crossdomain.xml文件即可。

這個文件中會規(guī)定哪些域可以訪問當(dāng)前服務(wù),看一個真實世界里的例子:




  
  
  
  
  
  
  
  
  
參考文章:

Same-origin policy

browsers

瀏覽器同源政策及其規(guī)避方法

security-with-canvas-elements

concept-canvas-origin-clean

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/87990.html

相關(guān)文章

  • 同源策略跨域方法

    摘要:同源策略的控制者是瀏覽器,瀏覽器可以控制不同域之間的資源的訪問或相互操作,但不控制自己對不同域之間的資源的操作和訪問。 同源與跨域 一般情況下,禁止一個域從另一個域讀取數(shù)據(jù),卻可以使用某些從其他域拿到的資源。比如說,允許一個域執(zhí)行、渲染、應(yīng)用從其他域獲取到的腳本、圖片、樣式;同樣,一個域可以展示從其他域獲取的內(nèi)容,比如在frame中顯示html文檔。網(wǎng)絡(luò)資源也可以選擇性的讓其他域來讀取...

    魏憲會 評論0 收藏0
  • 同源策略跨域知識點學(xué)習(xí)

    摘要:同源策略在這之前需要先熟悉一下這個概念,同源指請求協(xié)議相同,主機(jī)名相同,端口相同,涉及安全的策略。同源策略主要限制的是不同源之間的交互操作,對于跨域內(nèi)嵌的資源不受該策略限制。 問題起因是在使用weibo api的時候,發(fā)現(xiàn)有一個報錯。weibo api是https協(xié)議,我本地是模擬的回調(diào)域名,然后進(jìn)行數(shù)據(jù)通信,本地http協(xié)議,于是乎就報錯了。出于對postMessage的不是很熟悉,...

    baiy 評論0 收藏0
  • 同源策略跨域

    摘要:一些技術(shù)都默認(rèn)采取了同源策略,這些技術(shù)范圍包括但不限于。但是相比較以上的各種場景和繞過同源策略的方法,的跨域請求設(shè)置很容易,只需要在目標(biāo)服務(wù)的根目錄下 在前端開發(fā)的過程中,我們經(jīng)常遇到跨域的問題,以下的文章將列舉一下我在工作中碰到的跨域問題。以及稍稍的探討一下為什么會有跨域問題的出現(xiàn),和所謂的同源策略 同源策略 1. 歷史 1995 年由 Netscape 公司提出,之后被其他瀏覽器廠...

    Achilles 評論0 收藏0
  • 同源策略跨域

    摘要:一些技術(shù)都默認(rèn)采取了同源策略,這些技術(shù)范圍包括但不限于。但是相比較以上的各種場景和繞過同源策略的方法,的跨域請求設(shè)置很容易,只需要在目標(biāo)服務(wù)的根目錄下 在前端開發(fā)的過程中,我們經(jīng)常遇到跨域的問題,以下的文章將列舉一下我在工作中碰到的跨域問題。以及稍稍的探討一下為什么會有跨域問題的出現(xiàn),和所謂的同源策略 同源策略 1. 歷史 1995 年由 Netscape 公司提出,之后被其他瀏覽器廠...

    Seay 評論0 收藏0
  • 跨域跨域請求的方法

    摘要:存在跨域的情況網(wǎng)絡(luò)協(xié)議不同,如協(xié)議訪問協(xié)議。域名和域名對應(yīng)如訪問跨域請求資源的方法代理定義和用法代理用于將請求發(fā)送給后臺服務(wù)器,通過服務(wù)器來發(fā)送請求,然后將請求的結(jié)果傳遞給前端。定義和用法是現(xiàn)代瀏覽器支持跨域資源請求的一種最常用的方式。 1、什么是跨域? 由于瀏覽器同源策略,凡是發(fā)送請求url的協(xié)議、域名、端口三者之間任意一與當(dāng)前頁面地址不同即為跨域。存在跨域的情況: 網(wǎng)絡(luò)協(xié)議不同,...

    wwq0327 評論0 收藏0

發(fā)表評論

0條評論

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