6. SOP & CROS
在學完了 XSS 的「前端內鬼」與 CSRF 的「隔空偷襲」後,你一定會想說:「難道網頁世界裡,隨便一個外部網站都能對我的網站指手畫腳、或是偷看我網站的資料嗎?」
當然是沒可能!而在前線死死擋住這一切、保護所有網站隱私的幕後功臣,就是瀏覽器最核心的安全基石——同源政策(SOP,Same-Origin Policy)。
如果說 Cookie 屬性(如 HttpOnly、SameSite)是我們針對特定鑰匙加裝的鎖,那麼 同源政策就是瀏覽器內建的「網域防火牆」。
同源?
瀏覽器要判斷兩個網址是不是「自己人」,標準非常嚴格。兩個網址必須在以下三個元素完全一模一樣,才算是同源:
- 協定(Protocol):例如
http或https。 - 網域(Domain / Host):例如
ntub.edu.tw或google.com。 - 連接埠(Port):例如
:80或:443(如果沒寫,瀏覽器會根據協定自帶預設值)。
只要這三個元素中有任何一個字不一樣,瀏覽器就會判定它們是「不同源(Cross-Origin,跨來源)」。
以北商大官網 https://www.ntub.edu.tw 為例
| 比較網址 | 是否同源? | 原因判定 |
https://www.ntub.edu.tw/news | 🟢 同源 | 協定、網域、Port 完全一致,只有路徑(Path)不同。 |
http://www.ntub.edu.tw | ❌ 不同源 | 協定不同(http vs https)。 |
https://api.ntub.edu.tw | ❌ 不同源 | 網域不同(子網域 api 與 www 不同)。 |
https://www.ntub.edu.tw:8080 | ❌ 不同源 | 連接埠不同(:8080 vs 預設的 :443)。 |
同源政策到底在「限制」什麼?
很多初學者在寫 Next.js 或 Web API 串接時,常常會被同源政策搞得一頭霧水,以為跨網域什麼事都不能做。
同源政策主要限制的是「用 JavaScript 去讀取跨來源的資源與隱私」,它並不是限制網路連線本身。
具體來說,它有三大防禦戰場:
1. 限制 DOM 的操作
如果 Harry 的網頁裡用 <iframe> 嵌入了一個銀行的登入網頁,Harry 網頁上的 JavaScript 絕對沒有權限去撈取那個銀行 <iframe> 裡的任何按鈕、輸入框或是文字。否則駭客只要寫個隱藏的 iframe,就能用 JS 天天偷看你在別家網站輸入的密碼了。
2. 限制 Cookie 與儲存空間
如果你的瀏覽器裡同時開著「北商大系統」與「駭客網站」兩個分頁。駭客網站上的 JS 程式碼,絕對不可能透過 document.cookie 或 localStorage 去偷看或讀取北商大網域下的任何數據。
3. 限制 Fetch API 的「回應讀取」
這是最容易讓人誤解的地方!同源政策並不會阻止瀏覽器對其他網站發出請求。當你用 JS 發送 fetch('https://api.hacker.com') 時,瀏覽器其實「有」幫你把請求送出去,遠端伺服器也「有」收到並處理完、甚至把回應(Response)傳回給瀏覽器了。
當 Response 傳回瀏覽器的一瞬間,瀏覽器警鈴大作:「等等!發起請求的是 ntub.edu.tw,但回傳資料的是 api.hacker.com,這不同源!」於是瀏覽器一巴掌把資料攔截並銷毀,並在控制台(Console)噴出一行紅色的報錯,讓你的前端程式碼「讀取不到」這筆資料。
結合!
- 既然有了同源政策(SOP),駭客沒辦法在別的網域用 JS 偷讀取我的 Cookie,那為什麼 CSRF 還能成功?
- 因為 CSRF 攻擊利用的是瀏覽器的自動化機制(發出 Request 就順便帶 Cookie),它不需要「讀取」Cookie 的內容。駭客只是盲目地借用你的身份發送請求,而 SOP 只限制了「JS 去讀取回應」,並沒有限制瀏覽器「送出請求」,所以 SOP 擋不住 CSRF!
- 為什麼我們還需要防範 XSS?如果 XSS 成功,駭客把惡意 JS 代碼直接下毒塞進了「北商大系統」的內部。這時候,這段惡意的 JS 代碼就成了「北商大網域的內鬼」。
- 因為程式碼已經跟北商大系統「同源」了,同源政策會完全放行。這段內鬼代碼就能暢行無阻地讀取
document.cookie,把你的隱私偷走。這證明了「一旦被 XSS 破防,同源政策就會直接失效」。
- 因為程式碼已經跟北商大系統「同源」了,同源政策會完全放行。這段內鬼代碼就能暢行無阻地讀取
CORS
既然同源政策這麼嚴格,那現代前後端分離的架構(例如:前端 Next.js 部署在 Vercel my-app.vercel.app,後端 API 部署在 AWS api.my-app.com),前端不就永遠拿不到後端的資料了嗎?
為了解決這個實務上的正當需求,網頁世界允許後端伺服器「網開一面」,這個機制就叫做 CORS(跨來源資源共享,Cross-Origin Resource Sharing)。
- 運作原理:當前端跨網域 Fetch 資料時,後端伺服器必須在 Response Header 中,加上一張「通關特許證」:
Access-Control-Allow-Origin: https://my-app.vercel.app - 瀏覽器的放行條件:當瀏覽器收到 Response 時,看到這行 Header,發現後端大腦親口宣稱「我願意與這個前端共享資源」,瀏覽器才會解除 SOP 的限制,高高興興地把資料放行給前端的 JS 讀取。
問!
Q:小明在開發專案時遇到了跨網域報錯(CORS error)。他上網查到了一個偏方:在 Chrome 瀏覽器的捷徑後面加上參數
--disable-web-security(關閉瀏覽器安全檢查),重啟瀏覽器後,跨網域的報錯真的消失了,資料也能正常讀取。小明非常高興,準備把這個方法寫進他的專案部署說明書中。請用本章學到的「同源政策(SOP)」原理解釋:為什麼小明的方法是極度危險且不切實際的?真正的解決方案應該由誰(前端還是後端)來做調整?
- 答案引導建議:
- 危險與不切實際之處:同源政策(SOP)是運行在**「使用者(客戶端)的瀏覽器」**上的防禦機制。小明加參數只能關閉「他自己電腦上」的瀏覽器防禦。當其他正常的學生用標準的 Chrome 瀏覽器打開這個網站時,依然會被同源政策死死擋住。如果大家都關閉安全檢查,那麼任何一個釣魚網站都能輕易用 JS 偷走使用者的網銀 Cookie,世界將陷入資安災難。
- 真正解決方案:真正的解法必須由**後端伺服器(Application Server)**來做調整,在 Response 的 Header 中設定正確的
Access-Control-Allow-Origin政策(CORS),合法、安全地放行前端的跨網域請求。
小結
瀏覽器身為只是渲染和執行JS的地方,能這麼用心的保護我們實在是太感動了
(哭),但我們也講到了,SOP不能完全防禦前面學到的兩種超危險攻擊,最終還是要多種防禦方式並存 (CORS、轉意、SameSiteCookie …),大家開發時需要格外注意阿!
