在 Chrome 開發人員工具中實作 CSP 和 Trusted Types 偵錯功能

Kateryna Prokopenko
Kateryna Prokopenko
Alfonso Castaño
Alfonso Castaño

這篇網誌文章說明如何透過最近推出的「問題」分頁,針對內容安全政策 (CSP) 問題實作開發人員工具支援。

該實作工作是在 2 個實習機會期間完成: 1.一開始,我們打造了一般回報架構,並針對 3 個 CSP 違規問題設計問題訊息。 2. 第二步是新增 Trusted Type 問題,以及一些適用於「Trusted Types」偵錯的「開發人員工具」特殊功能。

什麼是內容安全政策?

內容安全政策 (CSP) 可讓您限制網站上的特定行為,以提高安全性。舉例來說,CSP 可用於禁止內嵌指令碼,或是禁止使用 eval,從而減少跨網站指令碼攻擊 (XSS) 攻擊的受攻擊面。如需 CSP 的詳細說明,請參閱這裡

「Trusted Types(TT)」(信任類型(TT) 政策) 特別是新的 CSP,可以啟用動態分析,以系統性的方式防止網站出現大量的注入攻擊。為達成此目標,TT 支援的網站掌控 JavaScript 程式碼,只允許將特定類型的項目指派給 DOM 接收器,例如 innerHTML。

網站可以透過加入特定的 HTTP 標頭來啟用內容安全政策。舉例來說 content-security-policy: require-trusted-types-for 'script'; trusted-types default 啟用網頁的 TT 政策。

每項政策都能在以下其中一種模式下運作:

  • 強制執行模式:錯誤會導致系統誤判。
  • 報表專用模式 - 將錯誤訊息回報為警告,但不會造成網頁失敗。

問題分頁中實作內容安全政策問題

這項工作的目標是改善 CSP 問題的偵錯體驗。評估新問題時,開發人員工具團隊大致遵循以下程序:

  1. 定義使用者故事。找出開發人員工具前端中的使用者故事,其中說明網頁程式開發人員如何調查問題。
  2. 前端實作。根據使用者案例,在前端找出調查該問題所需的資訊 (例如相關要求、Cookie 名稱、程式碼行或 HTML 檔案等)。
  3. 問題偵測。找出瀏覽器中在 Chrome 中偵測到問題的位置,然後指示回報問題的位置,並附上步驟 (2) 的相關資訊。
  4. 儲存及顯示問題。將問題保存在適當位置,並在開啟後提供給開發人員工具
  5. 設計問題文字,撰寫有助網頁程式開發人員瞭解的說明文字,更重要的是修正問題

步驟 1:定義 CSP 問題的使用者故事

開始實作前,我們先建立一份設計文件,內含使用者故事,以進一步瞭解需要採取的行動。舉例來說,我們會寫下以下使用者故事:


身為開發人員,我發現網站的部分內容被封鎖,我想:- - ...瞭解 CSP 是不是導致我網站上的 iframe / 圖片遭封鎖的原因 - ...瞭解哪些 CSP 指令導致特定資源遭到封鎖 - ...瞭解如何變更網站的 CSP,以允許顯示目前封鎖的資源 / 執行目前封鎖的 js。


我們製作了幾個簡單的範例網頁,當中呈現我們感興趣的 CSP 違規事項,並探索範例網頁,熟悉我們操作程序。 以下提供幾個網頁範例 (開啟「問題」分頁並開啟示範內容):

透過這個程序,我們發現來源位置是偵錯 CSP 問題最重要的資訊。我們也發現,在資源遭到封鎖的情況下迅速找出相關聯的 iframe 和要求會很有幫助,而開發人員工具「Elements」Elements面板中的 HTML 元素的直接連結可能也相當實用。

步驟 2:前端導入

我們將這項深入分析資訊轉換成初稿,希望透過 Chrome 開發人員工具通訊協定 (CDP) 提供給開發人員工具。

下方內容取自 third_party/blink/public/devtools_protocol/browser_protocol.pdl 摘錄

 type ContentSecurityPolicyIssueDetails extends object
   properties
     # The url not included in allowed sources.
     optional string blockedURL
     # Specific directive that is violated, causing the CSP issue.
     string violatedDirective
     boolean isReportOnly
     ContentSecurityPolicyViolationType contentSecurityPolicyViolationType
     optional AffectedFrame frameAncestor
     optional SourceCodeLocation sourceCodeLocation
     optional DOM.BackendNodeId violatingNodeId

上述的定義基本上是編碼 JSON 資料結構。是以簡單的語言編寫而成,名為 PDL (通訊協定資料語言)。PDL 有兩種用途。首先,我們使用 PDL 產生開發人員工具前端依賴的 TypeScript 定義。例如,上述 PDL 定義會產生下列 TypeScript 介面:

export interface ContentSecurityPolicyIssueDetails {
  /**
  * The url not included in allowed sources.
  */
  blockedURL?: string;
  /**
  * Specific directive that is violated, causing the CSP issue.
  */
  violatedDirective: string;
  isReportOnly: boolean;
  contentSecurityPolicyViolationType: ContentSecurityPolicyViolationType;
  frameAncestor?: AffectedFrame;
  sourceCodeLocation?: SourceCodeLocation;
  violatingNodeId?: DOM.BackendNodeId;
}

再者,更重要的是,我們會根據定義產生 C++ 程式庫,這個程式庫會從 C++ Chromium 後端對開發人員工具的後端產生及傳送這些資料結構。透過該程式庫,您可以使用以下 C++ 程式碼建立 ContentSecurityPolicyIssueDetails 物件:

protocol::Audits::ContentSecurityPolicyIssueDetails::create()
  .setViolatedDirective(d->violated_directive)
  .setIsReportOnly(d->is_report_only)
  .setContentSecurityPolicyViolationType(BuildViolationType(
      d->content_security_policy_violation_type)))
  .build();

瞭解要提供哪些資訊後,我們需要探索從 Chromium 中取得這些資訊的位置。

步驟 3:偵測問題

為了將資訊提供給 Chrome 開發人員工具通訊協定 (CDP),並以上一節所述格式提供給 Chrome ,我們需要在後端找到實際能取得該資訊的位置。幸好,CSP 程式碼已有用於報表專用模式的瓶頸,這是:ContentSecurityPolicy::ReportViolation 回報給 (選用) 報表端點的問題 (選用),可在 CSP HTTP 標頭中設定。我們想回報的資訊大多已經準備好,因此後端沒有重大的變更,因此不需擔心。

步驟 4:儲存及顯示問題

這項小小的小工具,是我們也想回報開發人員工具開啟前發生的問題,做法與控制台訊息的處理方式類似。換句話說,我們不會直接向前端回報問題,而是使用能獨立填入問題的儲存空間,不論開發人員工具是否為開啟。只要開啟開發人員工具 (或已附加其他 CDP 用戶端),就能從儲存空間重播先前記錄的所有問題。

後端工作已完成,接下來需要專注在前端的問題呈現方式。

步驟 5:設計問題文字

舉例來說,設計問題文字是一種流程,牽涉到多個團隊。舉例來說,我們經常仰賴實作某項功能的團隊 (在這個案例中為 CSP 團隊) 和 DevRel 團隊,決定網頁開發人員應如何處理特定類型的問題。問題文字通常會經過一些修正,直到更新完成。

一般來說,開發人員工具團隊會先對他們想像的內容進行粗略草稿:


## Header
Content Security Policy: include all sources of your resources in content security policy header to improve the functioning of your site

## General information
Even though some sources are included in the content security policy header, some resources accessed by your site like images, stylesheets or scripts originate from sources not included in content security policy directives.

Usage of content from not included sources is restricted to strengthen the security of your entire site.

## Specific information

### VIOLATED DIRECTIVES
`img-src 'self'`

### BLOCKED URLs
https://imgur.com/JuXCo1p.jpg

## Specific information
https://web.dev/strict-csp/

在疊代後,我們到達了:

ALT_TEXT_HERE

如您所見,讓功能團隊和 DevRel 一起提供更清晰準確的說明!

您也可前往專屬的 CSP 違規事項分頁,找出網頁上的 CSP 問題。

對信任類型問題偵錯

如果沒有合適的開發人員工具,就很難大規模使用 TT。

改善主控台列印功能

處理「信任的物件」時,我們希望顯示的資訊至少與不受信任的物件相同。可惜的是,目前在顯示信任的物件時,系統不會顯示包裝物件的相關資訊。

這是因為控制台中顯示的值預設是從物件呼叫的 .valueOf()。然而,若是信任類型,傳回的值就不實用。相反地,我們希望保留類似您呼叫 .toString() 時取得的結果。為此,我們必須修改 V8 和 Blink,為受信任的類型物件導入特殊處理功能。

雖然基於歷史因素,這項自訂處理作業是在 V8 中進行,但這種方法仍有重大的缺點。許多物件需要自訂顯示,但其類型在 JS 層級相同。由於 V8 是純 JS,因此無法區分與 Web API 對應的概念,例如可信類型。因此,V8 必須要求嵌入器 (閃爍) 才能區別。

因此,將這個程式碼的部分移到 Blink 或任何嵌入器聲音,就像是邏輯的選擇。除了暴露的問題之外,還有許多其他好處:

  • 每個嵌入器都可以產生自己的說明
  • 透過 Blink API 輕鬆產生說明
  • Blink 可存取物件的原始定義。因此如果使用 .toString() 產生說明,就不會有重新定義 .toString() 的風險。

違規事件發生 (在報表專用模式下)

目前,對 TT 違規進行偵錯的唯一方法,就是設定 JS 例外狀況的中斷點。由於強制執行 TT 違規會觸發例外狀況,因此這項功能或許非常實用。不過在實際情況下,您需要更精細地控管 TT 違規事件。具體來說,我們只是為了 TT 違規 (而非其他例外狀況) 的情況破例,在僅供報表模式下切斷,並區分不同類型的 TT 違規行為。

開發人員工具已支援多種中斷點,因此架構相當可擴充。如要新增中斷點類型,您必須變更後端 (閃爍)、CDP 和前端。 我們應推出新的 CDP 指令,命名為 setBreakOnTTViolation。前端會使用這個指令,告知後端應違反何種 TT 違規行為。後端 (特別是 InspectorDOMDebuggerAgent) 會提供「探測」,onTTViolation() 會在每次發生 TT 違規時呼叫。接著,InspectorDOMDebuggerAgent 會檢查該違規是否應觸發中斷點,如果是這樣,就會傳送訊息至前端,以暫停執行。

說明完成與後續行動

自本文所述問題發生以來,「問題」分頁已經過大幅變更:

我們計劃日後要透過「Issues」分頁來找出更多問題,以便長期停止在控制台中卸載無法讀取的錯誤訊息。

下載預覽頻道

建議您使用 Chrome CanaryDevBeta 版做為預設的開發瀏覽器。透過這些預覽版本,您可以存取開發人員工具中的最新功能、測試最先進的網路平台 API,以及找出網站的問題,以免使用者發現問題。

與 Chrome 開發人員工具團隊聯絡

請使用下列選項,討論貼文中的新功能和異動,或與開發人員工具相關的其他事項。

  • 歡迎透過 crbug.com 提出建議或意見。
  • 使用「更多選項」更多 > 回報開發人員工具問題說明 >在開發人員工具中回報開發人員工具問題
  • 前往 @ChromeDevTools 張貼 Tweet。
  • 歡迎在「開發人員工具」推出「最新消息」YouTube 影片或「開發人員工具秘訣」YouTube 影片留言。