同源政策 (Same Origin Policy) - 原理介紹

觀念:同源的資源才可互相存取,跨來源的資源則必須在某些特定情況下,才允許存取。

網站資源

首先先來了解什麼是網站資源:

  • 圖片
  • 影片
  • 程式碼

也就是說當打開一個網站的時候,網站上面的圖片、影片或是 HTML、CSS、JavaScript 等程式碼這些都是瀏覽器向伺服器主機下載下來的資源,而瀏覽器在將這些資源進行執行,最後呈現在網站的介面上供使用者使用。

而透過 JavaScript 程式碼,可以呼叫網路服務,來向伺服器請求提供更多資源。

同源政策介紹

之所以要有同源政策是為了要防範駭客的攻擊,因為有這個限制,在正常的情況下,駭客就不能夠任意用一個惡意的網站去呼叫其他網站的網路服務。

現今的大多數的瀏覽器都是內建實作同源政策,工程師是不需要去實作的。

看個例子:

利用 Chrome 開發者工具來試試看同源政策

打開網頁輸入 google.com 網址,並打開開發者工具的 console,輸入以下指令

1
2
# 發送HTTP Request GET請求facebook.com網站資源
fetch('https://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、domain、port 都一致,則代表被視為同源。

記住:必須一模一樣才行。

而在 DOM 同源政策有以下規定:

  1. 跨來源的寫入通常被允許

    例如:連結、重新導向、或是表單送出等動作,是被允許的。但如果直接使用 JavaScript 程式碼,例如:XMLHttpRequest or Fetch API 是無法跨來源寫入的。

  2. 跨來源的嵌入通常被允許

    例如:<img> 的影像、<video><audio> 媒體檔案、<frame> 以及 <iframe> 的內容,最後 CSS<link rel="stylesheet" href="..."> 跟 JavaScript 程式碼 <script src="...">\</script>

  3. 跨來源讀取通常不被允許

    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:

  1. domain
  2. path

只要兩者皆一致,則被視為同源的 Cookie,而 Cookie 可以加上 secure 設定,就會限定 Cookie 只能以 HTTPS 進行傳輸。

Cookie 同源政策有以下規定:

  1. 不同來源的 Cookie,會各自傳遞所屬的伺服器。

    怎麼看 Cookie 的來源呢?

    打開開發者工具,點選 Application,就可以在左邊看到 Cookies,點擊開來,可以看到很多的 Cookie,而點選其中一個 Cookie,就能看到該 Cookie 的詳細資料,如:

    • Name
    • Value
    • Domain
    • Path
    • Expire
    • Size
  2. 子網域與母網域的 Cookie 可以共用

    而他們各自存放的 Cookie 的 domain 分別就是

  • blog.example.com

    只要在子網域的 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

https://medium.com/@jaydenlin/same-origin-policy-%E5%90%8C%E6%BA%90%E6%94%BF%E7%AD%96-%E4%B8%80%E5%88%87%E5%AE%89%E5%85%A8%E7%9A%84%E5%9F%BA%E7%A4%8E-36432565a226

最後最後!請聽我一言!

如果你還沒有註冊 Like Coin,你可以在文章最下方看到 Like 的按鈕,點下去後即可申請帳號,透過申請帳號後可以幫我的文章按下 Like,而 Like 最多可以點五次,而你不用付出任何一塊錢,就能給我寫這篇文章的最大的回饋!