功能政策簡介

Eric Bidelman

摘要

功能政策可讓網頁開發人員選擇性啟用、停用及修改瀏覽器中特定 API 和網路功能的行為。CSP 類似,但它不是控制安全性,而是控制各項功能!

功能政策本身是開發人員和瀏覽器之間的使用者同意授權條款,旨在協助促進我們建構 (及維護) 優質網頁應用程式的目標。

引言

「為網路建構」是艱鉅的冒險,光是建構頂尖網頁應用程式來提升成效,並採用所有最新最佳做法,就已足夠了。長期持續提供良好的體驗也更難。隨著專案不斷演進,開發人員可以加入新的計畫、推出新功能,程式碼集也不斷成長。您之前獲得的 優質體驗 TM 可能會開始減損,使用者體驗會開始變差!功能政策可助您持之以恆。

你可以透過功能政策選擇使用一組「政策」,讓瀏覽器強制執行網站的特定功能。這些政策會限制網站可存取哪些 API,或修改瀏覽器對特定功能的預設行為。

以下列舉功能政策的用途:

  • 變更行動裝置和第三方影片的 autoplay 預設行為
  • 限制網站使用敏感 API,例如 cameramicrophone
  • 允許 iframe 使用 fullscreen API。
  • 禁止使用同步 XHR 和 document.write() 等過時的 API。
  • 確保圖片大小適當 (例如避免版面配置發生異常),且可視區域沒有太大 (例如浪費使用者的頻寬)。

政策是開發人員和瀏覽器之間的合約規定。應用程式會告知瀏覽器開發人員的意圖,因此當我們的應用程式嘗試出於軌道,執行一些不當行為時,我們就能誠實坦白。如果網站或內嵌的第三方內容試圖違反開發人員的任何預先選取規則,瀏覽器會以更好的使用者體驗覆寫該行為,或者完全封鎖 API。

使用功能政策

功能政策提供兩種控制功能:

  1. 透過 Feature-Policy HTTP 標頭。
  2. 在 iframe 上使用 allow 屬性。

如要使用功能政策,最簡單的方法是傳送含有頁面回應的 Feature-Policy HTTP 標頭。此標頭的值是您希望瀏覽器針對特定來源遵循的政策或一組政策:

Feature-Policy: <feature> <allow list origin(s)>

來源許可清單可採用以下幾個不同的值:

  • *:這項功能允許在頂層瀏覽環境和巢狀瀏覽內容 (iframe) 中運作。
  • 'self':這項功能可以在頂層瀏覽情境和相同來源巢狀瀏覽結構定義中使用。在巢狀瀏覽環境中的跨來源文件不允許使用。
  • 'none':頂層瀏覽情境不允許使用這項功能,且在巢狀瀏覽環境中不允許這項功能。
  • <origin(s)>:要啟用政策的特定來源 (例如 https://example.com)。

範例

假設您要封鎖所有內容,不讓網站使用 Geolocation API。方法是針對 geolocation 功能傳送嚴格的 'none' 許可清單:

Feature-Policy: geolocation 'none'

如果有一段程式碼或 iframe 嘗試使用 Geolocation API,瀏覽器會加以封鎖。即使使用者先前已授予分享位置資訊的權限也是如此。

違反已設定的地理位置政策
違反設定的地理位置政策。

在其他情況下,建議您稍微放寬這項政策。我們可以允許自有來源使用 Geolocation API,但限制第三方內容也無法存取,方法是在允許清單中設定 'self'

Feature-Policy: geolocation 'self'

iframe allow 屬性

使用功能政策的第二種方法是控制 iframe 中的內容。使用 allow 屬性指定嵌入內容的政策清單:

<!-- Allow all browsing contexts within this iframe to use fullscreen. -->
<iframe src="https://example.com..." allow="fullscreen"></iframe>

<!-- Equivalent to: -->
<iframe src="https://example.com..." allow="fullscreen *"></iframe>

<!-- Allow only iframe content on a particular origin to access the user's location. -->
<iframe
  src="https://another-example.com/demos/..."
  allow="geolocation https://another-example.com"
></iframe>

現有的 iframe 屬性會有什麼影響?

部分由功能政策控管的功能已有現有屬性,可控管這些功能的行為。舉例來說,<iframe allowfullscreen> 是一種允許 iframe 內容使用 HTMLElement.requestFullscreen() API 的屬性。此外,也有 allowpaymentrequestallowusermedia 屬性分別允許使用 Payment Request APIgetUserMedia()

請盡可能使用 allow 屬性,而非這些舊屬性。如果您需要使用 allow 屬性搭配對等的舊版屬性來支援回溯相容性,則幾乎沒有問題 (例如 <iframe allowfullscreen allow="fullscreen">)。請注意,限制更嚴格的政策則無需這麼做。舉例來說,以下 iframe 無法進入全螢幕,因為 allow="fullscreen 'none'"allowfullscreen 嚴格:

<!-- Blocks fullscreen access if the browser supports feature policy. -->
<iframe allowfullscreen allow="fullscreen 'none'" src="..."></iframe>

一次控管多項政策

如要同時控管多項功能,請使用 ; 分隔的政策指令清單來傳送 HTTP 標頭:

Feature-Policy: unsized-media 'none'; geolocation 'self' https://example.com; camera *;

也可以為每項政策分別傳送標頭:

Feature-Policy: unsized-media 'none'
Feature-Policy: geolocation 'self' https://example.com
Feature-Policy: camera *;

本範例會執行以下操作:

  • 禁止針對所有瀏覽情境使用 unsized-media
  • 禁止所有瀏覽情境使用 geolocation,頁面本身的來源和 https://example.com 除外。
  • 允許所有瀏覽環境的 camera 存取權。

範例:針對 iframe 設定多項政策

<!-- Blocks the iframe from using the camera and microphone
     (if the browser supports feature policy). -->
<iframe allow="camera 'none'; microphone 'none'"></iframe>

JavaScript API

雖然 Chrome 60 開始支援 iframe 的 Feature-Policy HTTP 標頭和 allow 屬性,但 Chrome 74 版新增了 JavaScript API

這個 API 可讓用戶端程式碼判斷網頁、頁框或瀏覽器可使用哪些功能。您可以在主要文件的 document.featurePolicy 底下存取成果,iframe 則是透過 frame.featurePolicy 存取。

範例

以下範例說明在 https://example.com 網站傳送 Feature-Policy: geolocation 'self' 政策的結果:

/* @return {Array<string>} List of feature policies allowed by the page. */
document.featurePolicy.allowedFeatures();
// → ["geolocation", "midi",  "camera", "usb", "autoplay",...]

/* @return {boolean} True if the page allows the 'geolocation' feature. */
document.featurePolicy.allowsFeature('geolocation');
// → true

/* @return {boolean} True if the provided origin allows the 'geolocation' feature. */
document.featurePolicy.allowsFeature(
  'geolocation',
  'https://another-example.com/'
);
// → false

/* @return {Array<string>} List of feature policies allowed by the browser
regardless of whether they are in force. */
document.featurePolicy.features();
// → ["geolocation", "midi",  "camera", "usb", "autoplay",...]

/* @return {Array<string>} List of origins (used throughout the page) that are
   allowed to use the 'geolocation' feature. */
document.featurePolicy.getAllowlistForFeature('geolocation');
// → ["https://example.com"]

政策清單

你可以透過功能政策控管哪些功能?

目前,我們沒有關於實作政策和使用方法的說明文件。隨著不同瀏覽器採用規格並導入各種政策,這份清單也會隨著時間增長。功能政策將成為動態目標,因此絕對需要優質的參考文件。

現在,您可以透過幾種方式查看哪些功能可控制。

  • 請參考功能政策廚房接收器提供的示範內容。並分別提供在 Blink 中實作的各項政策。
  • 如需功能名稱清單,請查看 Chrome 的來源
  • about:blank 上查詢 document.featurePolicy.allowedFeatures(),即可找到清單:
        ["geolocation",
         "midi",
         "camera",
         "usb",
         "magnetometer",
         "fullscreen",
         "animations",
         "payment",
         "picture-in-picture",
         "accelerometer",
         "vr",
        ...

如要判斷如何使用部分政策,請查看規格的 GitHub 存放區。其中包含關於部分政策的幾項說明。

常見問題

何時使用功能政策?

你可以選用所有政策,因此請視情況使用功能政策。舉例來說,如果您的應用程式是圖片庫,maximum-downscaling-image 政策可協助您避免將巨型圖片傳送至行動裝置可視區域。

如要使用 document-writesync-xhr 等其他政策,請多加註意。開啟這些功能可能會導致第三方內容 (例如廣告) 無法正常運作。另一方面,功能政策也可以只是普通的檢查,可確保您的網頁絕對不會使用這些 API!

我會在開發或正式版中使用功能政策嗎?

兩者並用。建議您在開發期間啟用政策,並在實際工作環境中讓政策保持啟用狀態。在開發期間啟用政策可協助您一開始就找到正確方向。它可協助您及早發現任何非預期的迴歸。請在實際工作環境中持續啟用政策,以確保使用者享有特定的使用者體驗。

有辦法向我的伺服器回報違反政策的情形嗎?

Reporting API 現已推出!與網站選擇接收 CSP 違規事項淘汰項目相關的報表的方式,您將可取得野外功能違反政策的報告。

iframe 內容的沿用規則為何?

指令碼 (第一方或第三方) 會繼承其瀏覽環境的政策。也就是說,頂層指令碼會沿用主要文件的政策。

iframe 會繼承上層頁面的政策。如果 iframe 具有 allow 屬性,則父項頁面和 allow 清單之間的政策將以較嚴格的政策為準。如要進一步瞭解 iframe 的使用方式,請參閱 iframe 中的 allow 屬性

不可以。這項政策的生命週期僅適用於單一網頁瀏覽回應。如果使用者前往新頁面,則必須在新回應中明確傳送 Feature-Policy 標頭,才能套用政策。

哪些瀏覽器支援功能政策?

請參閱 caniuse.com 瞭解瀏覽器支援的最新詳細資料。

目前,Chrome 是唯一支援功能政策的瀏覽器。不過,由於整個 API 介面皆可選擇採用或具備功能偵測,因此功能政策本身充分展現了逐步強化功能

結語

功能政策可協助您提供完善的途徑,藉此提高使用者體驗和效能。這在開發或維護應用程式時特別有用,因為可以協助防止潛在的足槍進入程式碼集。

其他資源