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

資訊專欄INFORMATION COLUMN

同源策略和跨域

Achilles / 2915人閱讀

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

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

同源策略 1. 歷史

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

同源策略只是一個(gè)規(guī)范,并沒有指定其具體的使用范圍和實(shí)現(xiàn)方式,各個(gè)瀏覽器廠商都針對(duì)同源策略做了自己的實(shí)現(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.

判斷同源的三個(gè)要素:

相同的協(xié)議

相同的域名

相同的端口號(hào)

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

舉個(gè)例子:

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

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

4. 限制范圍

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

無法共享 cookie, localStorage, indexDB

無法操作彼此的 dom 元素

無法發(fā)送 ajax 請(qǐng)求

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

其他

跨域

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

1. cookie

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

舉個(gè)例子,
https://market.douban.comhttps://book.douban.com,這兩個(gè)網(wǎng)頁的一級(jí)域名都是 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 中是可以取到這個(gè) cookie 的。

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

2. Ajax

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

針對(duì) 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 的運(yùn)作

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

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

簡單請(qǐng)求的判斷包括兩個(gè)條件:

請(qǐng)求方法必須是一下幾種:

HEAD

GET

POST

HTTP 頭只能包括以下信息:

Accept

Accept-Language

Content-Language

Last-Event-ID

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

不能同時(shí)滿足以上兩個(gè)條件的,就都視作非簡單請(qǐng)求

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

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

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

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

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

服務(wù)端

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

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

下面來說說這幾個(gè)字段都代表什么:

Access-Control-Allow-Origin

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

Access-Control-Allow-Credentials

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

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

另外,如果這個(gè)值被設(shè)為了true,那么Access-Control-Allow-Origin就不能被設(shè)置為 *,必須要顯示指定為origin的值;并且返回的cookie因?yàn)槭窃诒豢缬蛟L問的域名下,因?yàn)樽袷赝? 源策略,所以在origin網(wǎng)頁中是不能被讀取到的。

Access-Control-Expose-Headers

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

之所以會(huì)有這個(gè)字段,是因?yàn)樵?b>簡單請(qǐng)求中,response返回的頭信息中,瀏覽器只能拿到以下幾個(gè)基本字段:Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma

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

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

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

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

簡單請(qǐng)求最大的不同在于,非簡單請(qǐng)求實(shí)際上是發(fā)送了兩個(gè)請(qǐng)求。

預(yù)請(qǐng)求

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

瀏覽器

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

另外,還會(huì)帶上這幾個(gè)字段:

Origin: 同簡單請(qǐng)求origin

Access-Control-Request-Method: 請(qǐng)求將要使用的方法

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

服務(wù)端

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

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

Access-Control-Allow-Origin: origin

Access-Control-Allow-Methods: like request

Access-Control-Allow-Headers: like request

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

正式響應(yīng)

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

2.2 websocket

websocket 不遵循同源策略。

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

2.3 jsonp

jsonp 其實(shí)算是一種 hack 形式的請(qǐng)求。

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

3. iframe 3.1 iframe 中的同源策略

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

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

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

操作彼此的 dom

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

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

改變父/子級(jí)的 url

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

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

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

使用 window.name

跨文檔通信

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

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

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

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

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

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

3.3 使用 window.name

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

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

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

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

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

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

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

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

看一個(gè)簡單的例子:

// 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 的使用過程中,也會(huì)碰到同源策略的限制。

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

canvas.toDataURL

canvas.toBlob

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

例如:

// 這段 JS 運(yùn)行在 a.com 這個(gè)域名下
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)
    // 以下的這這三種操作都會(huì)報(bào)錯(cuò)
    canvas.toDataURL("image/jpg")
    canvas.toBlob(function () {})
    ctx.getImageData(0, 0, 10, 10)
}
img.src = src

運(yùn)行時(shí)會(huì)報(bào)錯(cuò)

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

可以看到是toDataURL的時(shí)候,因?yàn)?a.comb.com是不同源的兩個(gè)網(wǎng)頁,觸發(fā)了同源策略的限制。換成toBlobgetImageData會(huì)報(bào)同樣的錯(cuò)誤。

我們來探究以下報(bào)這個(gè)錯(cuò)誤的原因:

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

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

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

那么,這個(gè)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這個(gè)屬性,然后執(zhí)行,發(fā)現(xiàn)還會(huì)報(bào)個(gè)錯(cuò):

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

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

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

2.7 flash

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

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

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




  
  
  
  
  
  
  
  
  
參考文章:

Same-origin policy

browsers

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

security-with-canvas-elements

concept-canvas-origin-clean

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

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

相關(guān)文章

  • 同源策略跨域方法

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

    魏憲會(huì) 評(píng)論0 收藏0
  • 同源策略跨域知識(shí)點(diǎn)學(xué)習(xí)

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

    baiy 評(píng)論0 收藏0
  • 同源策略跨域

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

    ideaa 評(píng)論0 收藏0
  • 同源策略跨域

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

    Seay 評(píng)論0 收藏0
  • 跨域跨域請(qǐng)求的方法

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

    wwq0327 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<