###### tags: `Internet 網路知識與安全` # 跨來源資源共用 CORS (Cross-Origin Resource Sharing) 跨域問題主要是 `Server` 不同意 `Client` 存取改寫資料,要讓 `Server` 同意只能靠後端來解決。 :::spoiler 是一種使用額外 [HTTP](https://developer.mozilla.org/zh-TW/docs/Glossary/HTTP) 標頭令目前瀏覽網站的[使用者代理 (en-US)](https://developer.mozilla.org/en-US/docs/Glossary/User_agent "Currently only available in English (US)")取得存取其他來源(網域)伺服器特定資源權限的機制基於安全性考量,程式碼所發出的跨來源 HTTP 請求會受到限制。例如,[`XMLHttpRequest`](https://developer.mozilla.org/zh-TW/docs/Web/API/XMLHttpRequest) 及 [`Fetch`](https://developer.mozilla.org/zh-TW/docs/Web/API/Fetch_API "Fetch") 都遵守[同源政策(same-origin policy)] ::: ~~ > JSONP/常用的內容傳遞網路(content delivery networks, CDN)也是跨域的一種 --- ## 同源政策 (Same-origin policy) > 限制了程式碼和不同網域資源間的互動,自己的網站不能給別人存取和修改,目的是基於網路安全考量,防止被攻擊。 如何分辨是否同源 : 兩個來源 ( Origin ) 的 ==<font class="red">scheme、domain、port</font>== 三者相同,就會視為同源。 > Origin = scheme + domain + port * **scheme**(通訊協定,即為 http、https)。 * **domain**(域名,例如 google.com)。 * **port**(埠號,例如 :8000)。 以下與 ==<font class="red">https://example.com:8000</font>== 不同來源 : :::info http://example.com // 不同源,scheme 不同 https://example.org // 不同源,domain 不同 http://example.com:3000 // 不同源,port 不同 ::: --- ## 簡單請求 VS 非簡單請求 當 `Client` 與 `Server` 溝通時,需要以 `Request` 來取得 `Server` 回傳的 `Response`,其中請求的動作會再細分為兩種 : ### 1. **簡單請求(simple requests)** 僅允許下列 <font class="red">HTTP</font> 方法: * **GET** * **HEAD** * **POST** 僅允許以下欄位標頭值: * **Accept** * **Accept-Language** * **Content-Language** * **Last-Event-ID** ==<font class="red">屬於 Content-Type 欄位</font> :== * **application/x-www-form-urlencoded** (檔案內容) * **multipart/form-data** (檔案類型) * **text/plain** (纯文本格式) > 請求不會觸發 CORS 預檢,就會被稱為所謂的所謂的「簡單請求」。 ### 2. **非簡單請求 or 預檢請求(preflight request)** 請求為下列 <font class="red">HTTP</font> 方法其中之一: * **PUT** * **DELETE** * **CONNECT** * **OPTIONS** * **TRACE** * **PATCH** 為以下 <font class="red">Content-Type</font> 以外的標頭值: * **application/x-www-form-urlencoded** * **multipart/form-data** * **text/plain** > 發送請求時,瀏覽器發現是非簡單請求,因此先發出一個預檢請求 Options 方法來判斷請求是否安全,當伺服器端允許後,才能正式發送一開始的 Request。 --- ## 解決辦法 三個「治標不治本」的方法: * **關掉瀏覽器的安全性設置** 跨來源被擋住主要是因為瀏覽器的限制,因此可以透過關閉 `Google Chrome` 的安全性設置。 * **把 fetch mode 設成 no-cors** 在使用 `Fetch API` 時,出現跨域錯誤會提示使用 `no-cors` ,但是這個方法只是讓它不會報錯,依然拿不到 `Response` 。 * **不要用 AJAX 拿資料** 使用引入檔案的方式來拿資料,但是 2022 了,不會有人這樣使用,而且不方便。 :+1: 正確解決辦法 : :::success **後端加上** **Access-Control-Allow-Origin** Access-Control-Allow-Origin : `http://localhost:8081` (允許單個來源) Access-Control-Allow-Origin :`*` (允許全部來源) **Access-Control-Allow-Headers** Access-Control-Allow-Headers : `Content-Type` (解析Content-Type類型檔案) Access-Control-Allow-Headers : `*` (解析全部類型檔案) **Access-Control-Allow-Methods** Access-Control-Allow-Methods : `PUT` (允許單個方法) Access-Control-Allow-Methods : `*` (允許全部方法) **#需要帶上Cookie的情況** **Access-Control-Allow-Credentials : true** **Access-Control-Allow-Origin : http://localhost:8080** `帶上 Cookie 後,需給指定的來源,否則任何來源都能發出 Request 請求且帶上使用者的Cookie,會有安全性問題產生` **#存取自訂 Header** **Access-Control-Expose-Headers: X-List-Version** `Header 為自定義時` **#快取 preflight request** **Access-Control-Max-Age: 300** `快取300秒` `瀏覽器重複發出預檢,避免發生這種耗效能的情況,因此300秒內不會打到後端做預檢,而是直接沿用快取的資料` ::: :::info **Proxy Server (反向代理伺服器) :** 透過反向代理與客戶端溝通。但通常都是在工作上遇到此問題,因此不需要那麼費工費成本。 ::: <font class="red"></font> <style> .red { color: #CE0000; } </style>
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up