功能政策簡介

摘要

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

功能政策本身是開發人員和瀏覽器之間的選擇加入式協議,有助於我們達成建構 (及維護) 優質網頁應用程式的目標。

簡介

為網路建構應用程式是一項艱鉅的任務,要建構一款頂尖的網頁應用程式,並確保其效能優異且採用所有最新的最佳做法,本身就已經很困難。要持續提供優質體驗,更是難上加難。隨著專案演進,開發人員加入團隊,新功能陸續推出,程式碼集也會隨之增加。您曾經達成的「絕佳體驗」™ 可能開始惡化,使用者體驗也開始受到影響!這項政策旨在協助你依照計畫前進。

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

以下列舉幾個可透過功能政策執行的操作:

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

政策是開發人員與瀏覽器之間的契約。這些資訊可向瀏覽器說明開發人員的意圖,因此在應用程式嘗試偏離軌道並做出不當行為時,有助於我們保持誠實。如果網站或嵌入的第三方內容試圖違反開發人員預先選取的任何規則,瀏覽器會以更優異的使用者體驗覆寫該行為,或完全封鎖 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,瀏覽器會封鎖該程式碼或 iframe。即使使用者先前已授予分享位置資訊的權限,也是如此

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

在其他情況下,放寬這項政策或許是個不錯的做法。我們可以允許自己的來源使用 Geolocation API,但在許可清單中設定 'self',藉此防止第三方內容存取該 API:

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">) 即可。請注意,較嚴格的政策會勝出。舉例來說,由於 allow="fullscreen 'none'"allowfullscreen 更嚴格,因此下列 iframe 無法進入全螢幕模式:

<!-- 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 新增了對 Feature-Policy HTTP 標頭和 iframe 上的 allow 屬性的支援,但 JavaScript API 是在 Chrome 74 中新增的。

這個 API 可讓用戶端程式碼判斷網頁、框架或瀏覽器允許哪些功能。您可以透過 document.featurePolicy 存取主文件的內容,透過 frame.featurePolicy 存取 iframe 的內容。

範例

以下範例說明在網站 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",
        ...
  • 請前往 chromestatus.com,查看已在 Blink 中實作或正在考慮的政策。

如要瞭解如何使用上述部分政策,請查看規格文件的 GitHub 存放區。其中包含一些政策的說明。

常見問題

何時該使用功能政策?

所有政策都必須選擇加入,因此請在適當的情況下使用功能政策。舉例來說,如果您的應用程式是圖片庫,maximum-downscaling-image 政策可協助您避免將巨型圖片傳送至行動裝置的視區範圍。

document-writesync-xhr 等其他政策則應謹慎使用。開啟這些功能可能會導致廣告等第三方內容無法正常運作。另一方面,功能政策可做為檢查依據,確保網頁絕不會使用這些糟糕的 API!

我要在開發階段還是正式發布階段使用功能政策?

兩者皆是。建議您在開發期間啟用政策,並在正式版中保持政策處於啟用狀態。在開發期間啟用政策,有助於確保您一開始就走在正確的道路上。這有助於您在任何意外的回歸發生前先行偵測。在正式版中保持政策啟用狀態,確保使用者享有特定的使用者體驗。

有辦法向我的伺服器檢舉違反政策的內容嗎?

Reporting API 正在開發中!就像網站可以選擇接收有關CSP 違規淘汰的報告一樣,您也可以接收有關功能政策違規的報告。

iframe 內容的繼承規則為何?

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

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

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

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

如要瞭解最新的瀏覽器支援資訊,請參閱 caniuse.com

目前只有 Chrome 支援功能政策。不過,由於整個 API 途徑都是選擇加入或可偵測功能,功能政策非常適合漸進式增強功能。

結論

功能政策可協助您提供明確的路徑,以便提升使用者體驗和成效。在開發或維護應用程式時,這項功能特別實用,因為它可在潛在的陷阱進入程式碼集之前,協助您避免這些陷阱。

其他資源