Same-origin policy 的核心概念是瀏覽器預設讓一個來源的程式碼讀不到另一個來源的回應內容,而「來源」由協定、主機名與埠三者共同界定,任一項不同就是不同來源。它管的範圍是讀取:跨來源的請求照樣送得出去(表單送出、載入圖片、背景呼叫都會實際抵達伺服器),瀏覽器攔下的是把回應交還給發起的程式碼這一步。送得出去與讀不到之間的落差是 cross-site request forgery 得以成立的結構原因。

概念位置

Same-origin policy 是瀏覽器端各種跨來源判讀的地基,其餘機制都以它為參照點定義自己。CORS 是它的鬆綁協定——伺服器用回應標頭明說願意讓哪些來源讀取,於是放行的範圍由被讀的一方決定,而不是由想讀的一方主張。Cross-site scripting 走的是另一個方向:攻擊者的程式碼跑在目標來源之內,因此完全不受這條規則約束,所有以「別的來源讀不到」為前提的防護會一起失效。

有一項不一致要單獨記住,因為多數跨站防護的缺口都出在它上面:cookie 的作用域規則與來源的定義不同。Cookie 看的是網域與路徑,跨協定與跨埠共用,而 SameSite(限制 cookie 在跨站請求中送出的 cookie 屬性)判定「站」時用的是可註冊網域而非完整主機名——example.com 這一層,底下的 a.example.comb.example.com 都算在裡面。於是兩個不同來源(不同子網域)在同源政策下互相讀不到彼此的回應,在 cookie 的規則下卻屬於同一個站。這條落差是子網域被拿下之後 SameSite 不再構成防護的原因,判讀見 7.36 憑證在請求中怎麼帶

可觀察訊號與例子

要拿這條規則做判讀的訊號是前端回報拿不到回應,而伺服器的日誌顯示請求已經抵達並成功處理。這個組合直接指向讀取被擋,處置方向是伺服器端的 CORS 設定,與請求本身能不能送達無關。

預檢是另一種形態:瀏覽器在真正的請求之前先送出一個 OPTIONS 請求。這是瀏覽器對「超出表單原本就能發出的範圍」的請求先問過伺服器願不願意接受,伺服器沒有回答或回答不允許時,真正的請求根本不會送出——與請求已經抵達的那一種訊號不同,預檢被拒時連伺服器的業務日誌都不會留下紀錄。

設計責任

CORS 的允許來源要逐一具名。用萬用值放行所有來源時,任何網站上的程式碼都能讀到這個 API 的回應;而需要帶上憑證的跨來源請求另有一條硬性限制——瀏覽器要求伺服器明確指名來源,萬用值在這種請求上一律不被接受。

同源政策的保護對象是使用者的瀏覽器,不是伺服器的資料。它讓別的網站讀不到回應,攔不住任何不經過瀏覽器的呼叫——用命令列工具或伺服器端程式直接呼叫這個 API 時,這條規則從頭到尾不參與。授權判斷因此要完整地做在伺服器端,把 CORS 設定當成存取控制會在第一個非瀏覽器呼叫方出現時失效。分層的判讀見 7.29 API 認證的信任邊界分層