簡單弄懂同源政策 (Same Origin Policy) 與跨網域 (CORS)

前端小智發表於2021-12-28
作者: HannahLin
來源:medium
微信搜尋 【大遷世界】, 我會第一時間和你分享前端行業趨勢,學習途徑等等。
本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。

我相信每一個前端在對接 API 時,多多少少一定遇過以下錯誤:

image.png

雖然要解決此問題大部分還是需要後端幫忙,但前端也需要知道為什麼會發生、要如何解決。

同源政策 (Same Origin Policy)

image.png

同源政策是網站安全的基礎。 https://domain-a.com 只能存取自己網站裡的資源 (圖片、影片、原始碼代等),不允許網站 https://domain-b.com 來存取。想要存取跨來源資源必須在某些特定情況下才被允許。

image.png

畫清楚界線自己網站自己管,別人讀取不到也改不了。這很合理,不然若自己網站被別人任意修改、被惡意人士讀取機密資訊那就糟糕了!若沒有這層防護,壞人就可以任意新增刪除我們在各大社群裡面留言了、也可以輕易登入我們的銀行帳戶 ?。

怎麼判斷同不同源?

只要 schemedomainport 一樣就會被視為同源 (same-origin),其他則是不同源

image.png

若以 https://domain-a.com:80/hannah-lin 做範例,我們可以因此判斷跟以下是否同源:

http://domain-a.com → 不同源.scheme 不同
https://domain-a.com/mike → 同源
https://news.domain-a.com → 不同源.domain 不同
https://domain-a.com:81 → 不同源.port 不同
https://domain-b.com → 不同源.domain 不同

Note. IE 對於不同 port 會視為同源

但我網站明明就引入很多跨來源的資源啊?

網頁常見的跨來源資源真的不少,例如以下:

image.png

沒錯,在某些情況下跨來源是被允許的,不受同源策略限制

跨來源嵌入通常被允許 (embed)

像範例的 <script src=”…”></script><link rel=”stylesheet” href=”…”><iframe>、圖片 <img><video>、或是 @font-face <object><embed>.等等都是跨來源嵌入。

跨來源寫入通常被允許 (writes)

可以在藉由 <form>domain-a.com 發 request 給 domain-b.com,當然透過連結 links 或直接 redirect 到別的網站也是被允許的。

跨來源讀取通常被禁止 (reads)

domain-a.com 不能讀取 domain-b.com 的 cookie、XMLHttpRequest ,Fetch API 也都無法被讀取,會回報錯誤:

image.png

同源政策 (Same Origin Policy) 允許 HTML tag 產生的跨來源寫入 (write)/嵌入 (embed)/讀取 (read),但對於 JS 的跨來源 write/embed/read 是有限制的。

那什麼是 Cookie 的同源 ?

Set-Cookie: <cookie-name>=<cookie-value>
Set-Cookie: id=1234567; domain=hello.com

前端都知道 Cookie 是什麼,簡單來說就像一張通行證,通行證裡面會存有一組 Session ID 來驗證你身份,就像你加入某某俱樂部一樣,認卡不認人,誰擁有這張通行證就可以進入俱樂部。

Cookie 的同源跟以上所說的 DOM 同源有點不同 (圖片或是原始碼等資源被載入瀏覽器最後都會變成 DOM 的元素)

image.png

只要 domain 跟 Path 與 Cookie 上的一樣就會被視為同源。若經過一些設定才會判斷 scheme 要是 http 或 https。

// 加了 Secure 會限定此 Cookie 只能以 https 傳送
Set-Cookie: id=1234567; domain=hello.com; Secure
另外要注意的是子網域的 cookie 是可以存取到母網域 cookie 的 (api.domain-a.com 跟 domain-a.com cookie 可以被共用)

對了,同源政策是瀏覽器專屬,所以才會發生用 postman 可以拿到 API 回應但放到網站上就是會失敗的狀況。

CORS (Cross-Origin Resource Sharing)

CORS 翻成中文就是跨網域資源共享,也就是你可以用我資源我也可以用你的

image.png

為什麼會有 CORS

Same Origin Policy 雖然不錯,因為他防止了一些惡意的 script 攻擊,但總不會每一個跨網域都是惡意的; 也不可能一間公司擁有所有的資源,有時還是必須串接第三方資源,例如 Facebook API、Google Map、政府提供的公開 API 等。

怎麼設定

設定 CORS 相當容易,它其實只是 HTTP-Header 而已,這些設定基本上都是在後端,所以前端只需知道概念跟怎麼看 Responce Header 即可。

當前端用 fetchXMLHttpRequest 要存取資源時,在 request 之前都會先傳送 preflight request 確定 server 端有設定正確的相關 Http-Header,若檢查透過,才會實際發出 requeest。例如

fetch('https://xxx.com/data/', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  }
})

那 request header 會大概長這樣

POST /data/
Host: xxx.com
Origin: https://myweb.com
Content-Type: application/json

preflight reques 會大概是這樣:

OPTIONS /data/
Host: xxx.com
Origin: https://myweb.com/
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type

可以在 developer tools 中的 Network 看到相關的 Responce Header

image.png

當然後端可以把許可權開到最大讓任何人都可以讀取,不受同源政策的限制

Access-Control-Allow-Origin: *

但跨來源還是有許多風險的,所以建議還是不要直接 *

// 還是會針對特定網站開許可權
Access-Control-Allow-Origin: https://foo.example

// 可以設定允許哪些 method,defult 是全部方法
Access-Control-Request-Method: POST, GET

// 允許 client side 帶 cookie 等驗證,defult 是 false
Access-Control-Allow-Credentials: true

preflight request?

不是 simple request 都會先發一個 preflight request 確定 server 端有設定正確的相關 Http-Header,也就是會先問 server 是否允許這個 request,允許的話才會正式 request。像 HTTP PUT/DELETE method,或 Content-Type: application/json 都會先發 preflight request。

有同源政策的保護,我的網站就是安全的嗎 ?

答案:不能。

Same Origin Policy 只是最基本的保護而已,實際上 attackers 還是可以聰明地找到漏洞攻擊你的網站。例如 Cross-site scripting (XSS) 可以欺騙網站來繞過同源政策的保護,這是一個很大的問題,因為同源政策下瀏覽器信任底下所有資料存取都是安全的,但這樣被惡意注入利用很有可能就讓你網站掛掉,更嚴重是使用者敏感資料被洩漏,應該被保密的資料被壞人利用。

HTML5 Security Cheatsheet 這個網站蠻酷的,提供各種 XSS 變形手法程式以及範例可以上去玩玩看

image.png

要確保自己網站的安全,還是需要下功夫的,接下來也會介紹一些簡單的方法來保護你的網站!

程式碼部署後可能存在的BUG沒法實時知道,事後為了解決這些BUG,花了大量的時間進行log 除錯,這邊順便給大家推薦一個好用的BUG監控工具 Fundebug

原文:https://medium.com/starbugs/%...

交流

有夢想,有乾貨,微信搜尋 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。

本文 GitHub https://github.com/qq44924588... 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。

相關文章