普通文組 2.5

「X-Frame-Options、Same-origin policy、Cross-Origin Resource Sharing」相關筆記

原始問題

作品中插入 Linkedin、Facebook 與 Instagram 的超連結,為什麼在 codepen 右側欄位中點選這些超連結無法前往該網站?

在codepen的輸出視窗點擊超連結,無法連線至該網站

簡答

根據 DevTool Console 顯示的錯誤訊息,codepen.io 將X-Frame-Options設定為sameorigin,故無法在 codepen.io 的<iframe>中開啟不同來源(origin)的網站(Linkedin、Facebook 或 Instagram)

環境

Google Chrome: 89.0.4389.114 (Official Build) (64-bit)
os: Windows_NT 10.0.18363 win32 x64

X-Frame-Options

  • MDN: This indicate whether or not a browser should be allowed to render a page in a <frame>, <iframe>, <embed> or <object>.
    • deny: The page cannot be displayed in a frame, regardless of the site attempting to do so.
    • sameorigin: The page can only be displayed in a frame on the same origin as the page itself.
    • deny不允許載入任何頁面,而sameorigin允許載入同源的頁面
    • 將作品原始碼中超連結的href修改為 codepen.io 上其他作品的連結的話,可以在右側輸出欄位連線到該作品

問題解析

  • 在 codepen.io 處於 Editor View 模式時,作品是透過 codepen.io 網站中的<iframe>來展示

  • codepen.io 將X-Frame-Options設定為sameorigin,而 Linkedin、Facebook 或 Instagram 與 codepen.io 並不屬於相同來源,故無法在 codepen.io 的<iframe>中開啟這些網站

    Editor View模式下,作品透過codepen.io網站中的iframe元素展示

  • 如果使用 debug mode 來開啟 codepen.io 上的作品,此時作品不再透過<iframe>展示,且瀏覽器通常允許 cross-origin writes(下述),故可正常連線至其他網站

    使用Debug Mode開啟作品時,作品本身即是一個完整的HTML文件,而非嵌於codepen.io網站中的部分內容

定義 Same-origin policy

  • MDN: The same-origin policy is a critical security mechanism that restricts how a document (or script) loaded from one origin can interact with a resource from another origin.
  • Google Developers: The browser’s same-origin policy blocks reading a resource from a different origin.
  • CSRF Introduction and what is the Same-Origin Policy: Same-origin policy prevents scripts from one origin to access private data on another origin.

定義 origin

  • MDN: Two URLs have the same origin if the protocol, port (if specified), and host are the same for both.
    • Compares http://store.company.com/dir/page.html with the following URLs:
    URL Outcome Reason
    http://store.company.com/dir2/other.html Same origin Only the path differs
    http://store.company.com/dir/inner/another.html Same origin Only the path differs
    https://store.company.com/page.html Failure Different protocol
    http://news.company.com/dir/page.html Failure Different host
    http://store.company.com:81/dir/page.html Failure Different port (http:// is port 80 by default)

筆記

  • Same-origin policy 是瀏覽器提供的安全政策,會限制一個網站只能與相同來源的文件或 script 互動
  • 何謂相同來源?兩組 URL 若符合以下條件,則視為屬於同樣來源:
    • 擁有相同的 protocol(都是 HTTP 或 HTTPS)
    • 擁有相同的 host(domain)
    • 擁有相同的 port

例外

參考MDN: Cross-origin network access

  • 瀏覽器通常允許 cross-origin writes(顯示資料),比如:開啟不同來源的網站,或是送出表單
  • 瀏覽器通常允許 cross-origin embedding,比如:
    • 透過<script src="…"></script>嵌入不同來源的 JavaScript
    • 透過<link rel="stylesheet" href="…">嵌入不同來源的 CSS
    • 使用@font-face載入不同來源的字型資源
    • 使用<audio><img><video><iframe><object><embed>載入不同來源網站的資源

定義 Cross-Origin Resource Sharing (CORS)

  • MDN: CORS is an HTTP-header based mechanism that allows a server to indicate any other origins (domain, scheme, or port) than its own from which a browser should permit loading of resources.
  • Google Developers: Enabling CORS lets the server tell the browser it’s permitted to use an additional origin.
    • When you want to get a public resource from a different origin, the resource-providing server needs to tell the browser “This origin where the request is coming from can access my resource”. The browser remembers that and allows cross-origin resource sharing.

處理方式

流程如下:

  1. 設定 server 的 HTTP response headers 來讓瀏覽器知道可以執行 CORS
  • 以 Express 為例:加上cors()
var express = require("express");
var cors = require("cors");
var app = express();

app.use(cors()); // 讓server允許CORS

app.get("/products/:id", function (req, res, next) {
  res.json({ msg: "This is CORS-enabled for all origins!" });
});

app.listen(80, function () {
  console.log("CORS-enabled web server listening on port 80");
});
  1. 透過瀏覽器發出 request 的時候,header 需包含Origin資訊
  1. server 收到包含Origin資訊的 header、並 server 本身允許 CORS 時,server 發出的 response header 就會包含Access-Control-Allow-Origin的 key-value pair;*代表允許來自任何 URL 的 CORS,或是字串(僅允許特定 URL 進行 CORS)
  2. 瀏覽器收到 response header,並Access-Control-Allow-Origin的值允許客戶端 CORS 的話,就會將 server 回覆的內容提供給客戶端

參考文件