同源政策 (Same Origin Policy) - 原理介紹
觀念:同源的資源才可互相存取,跨來源的資源則必須在某些特定情況下,才允許存取。
網站資源
首先先來了解什麼是網站資源:
- 圖片
- 影片
- 程式碼
也就是說當打開一個網站的時候,網站上面的圖片、影片或是 HTML、CSS、JavaScript 等程式碼這些都是瀏覽器向伺服器主機下載下來的資源,而瀏覽器在將這些資源進行執行,最後呈現在網站的介面上供使用者使用。
而透過 JavaScript 程式碼,可以呼叫網路服務,來向伺服器請求提供更多資源。
同源政策介紹
之所以要有同源政策是為了要防範駭客的攻擊,因為有這個限制,在正常的情況下,駭客就不能夠任意用一個惡意的網站去呼叫其他網站的網路服務。
現今的大多數的瀏覽器都是內建實作同源政策,工程師是不需要去實作的。
看個例子:
利用 Chrome 開發者工具來試試看同源政策
打開網頁輸入 google.com 網址,並打開開發者工具的 console,輸入以下指令
1 | # 發送HTTP Request GET請求facebook.com網站資源 |
會看到以下的錯誤訊息
1 | Access to fetch at 'https://facebook.com/' from origin 'https://www.google.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled. |
我們可以看到錯誤訊息寫 has been blocked by CORS policy,也就是在同源政策的阻擋下,不允許這樣的跨來源存取。
同源政策的分類
而同源政策又分成兩種類型:
DOM 的同源政策
可以知道圖片、影片或是程式碼等資源,最終都是被瀏覽器載入,會變成 DOM 元素。
在 DOM 的同源政策中,網站怎麼判斷是否同源呢:
舉個例子:
https://hello.example.com:80/info
-
scheme
就是 http 或 https
-
domain
-
port
就是 80
-
path
就是 profile
只要 scheme、domain、port 都一致,則代表被視為同源。
記住:必須一模一樣才行。
而在 DOM 同源政策有以下規定:
-
跨來源的寫入通常被允許
例如:連結、重新導向、或是表單送出等動作,是被允許的。但如果直接使用 JavaScript 程式碼,例如:XMLHttpRequest or Fetch API 是無法跨來源寫入的。
-
跨來源的嵌入通常被允許
例如:
<img>
的影像、<video>
、<audio>
媒體檔案、<frame>
以及<iframe>
的內容,最後 CSS<link rel="stylesheet" href="...">
跟 JavaScript 程式碼<script src="...">\</script>
。 -
跨來源讀取通常不被允許
JavaScript 透過 XMLHttpRequest or Fetch API,進行跨來源讀取是不被允許的。那跟跨來源的嵌入差別又在哪裡呢?
看個例子:
打開 yahoo.com 首頁,然後打開開發者工具,選取 Network,並點選 XHR,可以看到有很多網站服務,假設點第一個網站服務:
點選第一個 name:
https://guce.yahoo.com/v1/consentRecord?consentTypes=iab%2CoathVendorsConsent&oathVendorIds=106
並按右建 copy 這個網址。
在打開另一個網站,例如:google.com
假設我要把中間 Google 的圖案換成這個剛剛臉書那個網站服務拿到的程式碼把它嵌入進去:
也就是換成
<iframe src="剛剛複製的網站服務網址">\</iframe>
。但如果我們在 google.com 用開發者工具打開 console 並輸入以下內容:
1
fetch("https://guce.yahoo.com/v1/consentRecord?consentTypes=iab%2CoathVendorsConsent&oathVendorIds=106")
會看到前面所看到被同源政策阻擋的錯誤,而不允許存取。但跨來源嵌入的內容卻是可以直接顯示在瀏覽器中,而其內容是無法被 JavaScript 程式碼讀取的。
總結特性:
- 同源政策對於 HTML tag 產生的跨來源寫入 / 嵌入 / 讀取是允許的,
- JavaScript 程式碼產生的跨來源寫入 / 嵌入 / 讀取是有限制的
Cookie 的同源政策
這個同源政策主要是針對 Cookie 這項資源的規範。
在這邊要如何判斷是否是同源的 Cookie:
- domain
- path
只要兩者皆一致,則被視為同源的 Cookie,而 Cookie 可以加上 secure 設定,就會限定 Cookie 只能以 HTTPS 進行傳輸。
Cookie 同源政策有以下規定:
-
不同來源的 Cookie,會各自傳遞所屬的伺服器。
怎麼看 Cookie 的來源呢?
打開開發者工具,點選 Application,就可以在左邊看到 Cookies,點擊開來,可以看到很多的 Cookie,而點選其中一個 Cookie,就能看到該 Cookie 的詳細資料,如:
- Name
- Value
- Domain
- Path
- Expire
- Size
-
子網域與母網域的 Cookie 可以共用
-
母網域網址:http://example.com
-
子網域網址:http://blog.example.com
而他們各自存放的 Cookie 的 domain 分別就是
-
-
只要在子網域的 Cookie 的 domain 改成 **.example.com**,當在子網域發送 HTTP REQUEST 的時候,就會一併把母網域跟子網域的 Cookie 一併送出。
而透過 JavaScript 程式碼:
1 | document.cookie |
也就可以存取 cookie,所以當子網域網站被攻擊,可能會連帶影響母網域的網站。
安全議題
-
DOM 的同源政策會被利用在 CSRF 類型的攻擊
例如:
1
2
3
4<from action="http://bank.com/transfer">
<input>....
<input>....
</from>在這種情況下,就會導致請求跨域接口。
-
Cookie 的同源政策沒有去限制子網域可以去修改或是存取母網域的 Cookie
因為許多網站母網域跟子網域的 Cookie 其實是會互相共用的,就會造成可攻擊的缺口。
總結
網站資安其實是一件很重要的事情,但是我卻很少去深入去了解,這對於開發網站的工程師是相當不及格的,所以藉此寫筆記紀錄一下,後續會持續發有關資安的文章的~
參考資料:
https://developer.mozilla.org/zh-TW/docs/Web/Security/Same-origin_policy
最後最後!請聽我一言!
如果你還沒有註冊 Like Coin,你可以在文章最下方看到 Like 的按鈕,點下去後即可申請帳號,透過申請帳號後可以幫我的文章按下 Like,而 Like 最多可以點五次,而你不用付出任何一塊錢,就能給我寫這篇文章的最大的回饋!