iT邦幫忙

2024 iThome 鐵人賽

DAY 11
0
Software Development

全端實戰心法:小團隊的產品開發大小事系列 第 11

何謂 CORS?網站開發該懂的網路知識

  • 分享至 

  • xImage
  •  

你是否有在開發網站時遇過 CORS 的錯誤?

像是架了一個後端的 API Server,但是在開發前端時送出 Request 卻遇到類似下面的錯誤

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://locahost:6789

什麼叫做 Cross-Origin,為何 Request 被 Block 住了?但是我用 Postman 這樣的工具明明就可以成功得到 Response 呀!

今天就讓我們來談談網站開發該懂的 CORS。

CORS

所謂 CORS 是 Cross-Origin Resource Sharing(跨來源資源共用)的簡稱,大部分的開發者多少都聽過這個很繞口的機制,也知道這是在網頁送出請求後,因為某種原因讓你收不到回覆的安全機制。

我們先來看看這個情境:伺服器在 Domain A,用戶透過瀏覽器查閱 Domain B 的網頁,但在 Domain B 的網頁中送出了一個往 Domain A 的請求。在沒有額外設定的情況下,以下兩種狀況哪個正確?

  1. 在 Domain A 的伺服器會拒絕從 Domain B 的網頁來的請求

  2. 在 Domain A 的伺服器會回覆請求,但在 Domain B 頁面的瀏覽器會拒絕此回覆

答案是 2,拒絕者是瀏覽器而非伺服器。我們可以試著用非瀏覽器的程式對伺服器送出請求,例如用 Postman 模擬從 Domain B 送出請求,結果發現能成功拿會 Response,這便代表伺服器實際上是有回覆的。

Request-Response in different domain
*Request-Response in different domain

為何?難道在 Domain A 的 Server 不該阻擋不是同個 Domain 的請求嗎?可能不該,而且也無法。

這其實便關於我們前面提過的同源政策,不該的原因是提供 API 服務的伺服器原本就有可能接收來自不同網站的請求,例如提供第三方登入的 Auth Server 就是一個例子,總不能只容許 Auth Server 接收相同 Domain 的網頁請求吧;而無法的原因則是來源頁面的 Domain 在傳輸封包的過程中,僅僅只是加上一個叫做 Origin 的 Header,我們在開發時使用的 Postman 就能夠輕鬆修改這個 Header 來模擬從某網頁送出的請求。

因此,瀏覽器就負起這個責任,來擋住和當前瀏覽 Domain 不同來源的回覆。瀏覽器會預設你所要送出請求 Server 的 Domain 要和正在瀏覽的相同,才會接受伺服器的回覆,這是為了預防有惡意的 Script 將當前網頁的一些機密資訊。

我們知道瀏覽器可以儲存當前網頁 Domain 相關資訊在 Cookies 或 Local Storage 中,例如登入的 Token,並在送出請求時攜帶此 Token 來維持登入狀態。此時惡意 Script 就可以透過已登入的資訊來獲取資訊。

等到拿到這些機敏資料後,再把這些資料傳到駭客自己的伺服器中,而瀏覽器就會是個中繼點。但有了 CORS 機制的幫助,瀏覽器發現回覆的 Domain 和當前的不同,就會阻止 Script 接收到這些資料,從而避免了一次攻擊。

設定 Access-Control-Allow-Origin,開發階段的痛楚

但就是因為瀏覽器的這個安全機制,我們在開發階段時總是繞不開這個常見的錯誤。

由於在前端開發時,通常會啟動一個 Dev Web Server 來 Serve 前端的 JavaScript、HTML、CSS 等靜態檔案給瀏覽器,此 Server 常與提供 API 的後端 Server 有著不同的 Domain。就算都 Host 在本機的 Localhost 上,CORS 的 Policy 規定只要 Port 不同,也不算在同個 Domain。

此時常見的做法就是在後端回覆的 Header 加上 Access-Control-Allow-Origin: *,讓收到回覆的 Browser 知道這個 API Server 允許所有來源的請求得到回覆,這樣在前端開發時就能成功獲取的想要的資訊了。

然而在這樣設定之後,就要記得在實際要 Release 的 Production 環境關閉這樣的設定,否則就會有資安的隱患。

區分測試環境及實際生產環境的 CORS 設定
*區分測試環境及實際生產環境的 CORS 設定

最好的做法是在實際生產環境中的 Access-Control-Allow-Origin 設定白名單,例如 production-client.com 是我們的前端的來源 Domain,便只 Allow 此 Domain。

在設定完白名單後,Server 同時還要給予 Access-Control-Allow-Credentials: true 的 Header,讓 -client.com 的用戶在後續的 Request 中能夠附帶 -server.com 的 Cookies。


上一篇
登入系統(五):淺談資訊安全,同源政策及 XSS、CSRF
下一篇
不寫演算法,也該懂的時間複雜度
系列文
全端實戰心法:小團隊的產品開發大小事13
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言