HTML 的 crossorigin 屬性 及 HTTP 回應檔頭的 Access-Control-Allow-*
要引入其他網站的資料時,有時會遇到同源政策 (same-origin policy) 的限制。
最常見的就是在設計 A 網站時,想要使用者在瀏覽時引用 B 網站的資料,但是前端卻出現這樣的錯誤:
Access to script at ‘https://bbb.com' from origin ‘https://aaa.com' has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
先說前提:要引用資料,一定要 B 網站的配合。不可能僅編輯 A 網站就成功讓瀏覽器可以在 A 網站的頁面中引用 B 網站的資料。
這是基於安全考量而有的限制,原因不在此文贅述。而是做些下述筆記。
前備知識:「HTTP 回應檔頭」(response header) 並不是 HTML 的一部分,所以對網頁進行「檢視原始碼」也是看不到的。如果你只能編輯 HTML ,那麼是沒法解決前述問題的。請到別處學習「 HTTP 連線的請求與回應」的相關知識。
HTTP 回應檔頭的 Access-Control-Allow-*
意義:
於前述跨源請求(A網站跟瀏覽器說「請去跟B網站要資料」,而後瀏覽器向B網站發出請求)時,
被請求資源的伺服器(B網站)會表示此資源是否有設計讓來源(A網站)進行跨源請求。
Access-Control-Allow-Origin:僅能為*或一個來源名。若需要允許多個來源存取資源,即要設計為針對不同來源做出不同回應檔頭。
雖然規格上允許設為null,但 MDN 表示那會被視為跟data:和file:同源而有安全疑慮。Access-Control-Allow-Credentials:要設定的話就只能為true,不然就是省略這個檔頭。若有設定此檔頭,則Access-Control-Allow-Origin不可為*。
由於 CORS 的請求檔頭應要包含 Origin ,所以 Access-Control-Allow-Origin 直接回傳域名即可。以 PHP 為例:
1 |
|
HTML 的 crossorigin 屬性
意義:
在 A 網站的頁面中要引入 B 網站的資源時,瀏覽器會依 A 網站中的此屬性而對 B 網站的請求與回應有不同的措施。
此設計同於 fetch() 或 XMLHttpRequest 請求跨源資源時的限制。
適用標籤:<audio>, <img>, <link>, <script>, <video>
不同的設置情形:
| 設定值 | 請求檔頭的 Origin |
回應檔頭的 Access-Control-Allow-Origin |
回應檔頭的 Access-Control-Allow-Credentials |
|---|---|---|---|
| 不設定 | 不存在 | 隨便 | 可不存在 |
anonymous 、留白或其他 |
存在 | 須為 * 或 源名 |
可不存在 |
use-credentials |
存在 | 須為源名 | true |
總地來說,僅有「不設定」、「設為 use-credentials 」、「其他均視為 anonymous」 三種情形。
其中「源名」指前述A網站的網址中,從同訊協定(https)到網域名稱結尾,但不包含路徑開頭的斜線的部分。
與 referrerpolicy 不太有關係
這二者均是在指示瀏覽器,在存取後續(或當前網頁的內嵌)資源時,是否要調整 HTTP 檔頭。crossorigin 並會指示瀏覽器,對伺服器的回應進行檢查。
| 差別 | referrerpolicy | crossorigin |
|---|---|---|
| 適用的存取對象 | 所有資源 | 跨源資源 |
| 影響的請求檔頭 | Referer |
Origin |
| 檢查回應檔頭 | 不檢查 | 可能檢查 Access-Control-Allow-Origin 和 Access-Control-Allow-Credentials |
試想在 https://aaa.com/foo.html 的網頁有這樣的 HTML :
1 | <script src="https://bbb.com/x.js" crossorigin="anonymous"></script> |
由於有設定 crossorigin 屬性,瀏覽器會使用 CORS 連線。
這個意思是,請求檔頭會有一個 Origin: https://aaa.com 。
但關於「A網站跟瀏覽器說『請去跟B網站要資料』」這件事,一般瀏覽器對 B 網站連線時,還會傳送 referer 檔頭: Referer: https://aaa.com/ 。
雖然在一般情形下, Origin 和 Referer 是差不多的(預設情形下會差那個斜線),但請務必注意其目的不同:
- Origin 是針對同源政策而設計出來的東西,僅考量協定、主機名、埠號(通常會省略,表示使用域設埠號)
- Referer (注意這個字是拼錯的)是為了傳遞「前一個網頁的(完整)網址是啥」,是早期為了統計網路流量的設計。後來考量隱私,現今瀏覽器在跨源的時候會預設為僅傳送根目錄(包含最後的斜線)。
若要指示讓瀏覽器傳送不同詳細程度的 Referer ,則可以設定 referrerpolicy 屬性(注意後者的 referrer 是拚對的),參閱前一篇文。
個人意見
- 若不想讓B網站知道「訪客是從A網站連過去的」的話,就要設定
referrerpolicy="same-origin",但不能設定crossorigin。
不過 MDN 說<link>的情形下,Request with no appropriate crossorigin header may be discarded. - 若要運作「會被其他網站引用的資源」的伺服器(例如CDN),且僅為特定來源設計,可以在來源不明(或已被列入黑名單)時直接拒絕請求,而根本不用告知
Access-Control-Allow-*。