同源政策 Same-origin policy 是在Web瀏覽器中,允許某個網頁指令碼也就是 javascript 訪問另一個網頁的資料的前提是,這兩個網頁必須有相同的URI、主機名和埠號,一旦兩個網站滿足上述條件,這兩個網站就被認定為具有相同來源。在 same origin policy 的限制下,能限制瀏覽器防止某個網頁上的惡意指令碼通過該頁面的文件物件模型存取另一網頁上的敏感資料。
滿足同源的條件有三個
使用相同的通訊協定 http/https
有相同的網域 domain
有相同的 port
跨來源請求 cross-origin http request,就是在非同源的情況下,發生的 http request,在發生這種狀況時,必須要遵守 CORS (Cross-Origin Resource Sharing) 的規範
定義
CORS 就是針對非同源的 http request 制定的規範,當 javascript 存取非同源的資源時, server 必須明確告知瀏覽器,是否允許這樣的 request,只有 server 允許的 request 能夠被瀏覽器發送,否則就會失敗
CORS 的跨來源請求有兩種:「簡單」與「非簡單」
跨來源請求
「簡單」跨來源請求有兩個條件
只能使用 GET, POST, HEAD method
http reques header 只能有
Accept
、Accept-Language
、Content-Language
或Content-Type
,且 Content-Type 只能是application/x-www-form-urlencoded
、multipart/form-data
或text/plain
只要不是「簡單」跨來源請求,就是「非簡單」跨來源請求
簡單請求 simple requests 不會觸發 CORS 預檢 preflighted
sample
以下是一個 cross-origin request/response,可發現在 request 裡面,會有一個 Origin http header
Origin 標記,這是來自 http://foo.example 的 cross-orign request
GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: http://foo.example/examples/access-control/simpleXSInvocation.html
Origin: http://foo.example
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2.0.61
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml
[XML Data]
下面的 response 有 Access-Control-Allow-Origin
這個 header,* 表示server 允許來自任意 origin 的 http request
預檢 preflighted request
「非簡單」request,在瀏覽器真正發送 request 之前,會先發送一個 preflight request,用途是詢問 server 是否允許這樣的 request
preflighted request 是用 http OPTIONS method 產生的
在 request 會有這兩個 header
Access-Control-Request-Method:該 request 是哪一個 http method
Access-Control-Request-Headers:該 request 裡面待有哪些非簡單的 http header
OPTIONS /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
response 有以下重點
Access-Control-Allow-Origin:允許的 origin
Access-Control-Allow-Methods:允許的跨 origin http method
Access-Control-Allow-Headers:允許使用的 http header
Access-Control-Max-Age:本次預檢請求回應所可以快取的秒數,代表 browser 可 cache 這個 response 多久
cookie
通常 CORS 不允許使用 cookie,也不支援 redirect
如果真的還是要使用 cookie
fetch API 要加上 credentials
fetch('https://othersite.com/data', {
credentials: 'include'
})
XMLHttpRequest 要加上 withCredentials = true
const xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.open('POST', 'https://othersite.com/data');
server 端也要增加一個 response header
Access-Control-Allow-Credentials: true
使用 cookie 時,Access-Control-Allow-Origin
不能直接填寫 *
必須明確標示哪些 origin 可以使用 cookie
沒有留言:
張貼留言