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

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

本文將說明如何透過最近推出的「Issues」分頁,實作 DevTools 支援功能,以便偵錯內容安全政策 (CSP) 問題。

實作工作是在 2 次實習期間完成:在第一階段,我們建立了一般報表架構,並設計了 3 個 CSP 違規問題的問題訊息。2. 在第二次測試期間,我們新增了信任類型問題,以及一些專門用於信任類型偵錯的 DevTools 功能。

什麼是內容安全政策?

內容安全政策 (CSP) 可限制網站中的特定行為,以提升安全性。舉例來說,CSP 可用於禁止內嵌指令碼或 eval,這兩者都能減少跨網站指令碼 (XSS) 攻擊的攻擊面。如要進一步瞭解 CSP,請參閱這篇文章

Trusted Types(TT) 政策是一種特別的新 CSP,可啟用動態分析,有系統地防範網站上大量的注入攻擊。為達成這項目標,TT 支援網站監控 JavaScript 程式碼,只允許將特定類型的項目指派給 DOM 接收器,例如 innerHTML。

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

每項政策可採用下列其中一種模式運作:

  • 強制模式:每項政策違規都會產生錯誤
  • 僅回報模式:將錯誤訊息回報為警告,但不會導致網頁失敗。

在「Issues」分頁中實作內容安全政策問題

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

  1. 定義使用者案例。在開發人員工具前端中找出一系列使用者故事,說明網路開發人員如何調查問題。
  2. 前端實作。根據使用者故事,找出前端調查問題時需要哪些資訊 (例如相關要求、Cookie 名稱、指令碼或 HTML 檔案中的一行)。
  3. 問題偵測。找出瀏覽器中可在 Chrome 中偵測到問題的位置,並檢測該位置,以便回報問題,並附上步驟 (2) 中的相關資訊。
  4. 儲存並顯示問題。將問題儲存在適當位置,並在開發人員工具開啟時提供這些問題
  5. 設計問題文字。提供說明文字,協助網頁開發人員瞭解並解決問題

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

在開始實作工作之前,我們先建立了設計文件,並加入使用者故事,以便進一步瞭解我們需要執行的作業。舉例來說,我們記錄了以下使用者故事:


身為開發人員,我剛發現網站的某些部分遭到封鎖,因此想:- - ...找出 CSP 是否是導致網站上 iframe / 圖片遭到封鎖的原因 - ...瞭解哪個 CSP 指示會導致特定資源遭到封鎖 - ...瞭解如何變更網站的 CSP,以便顯示目前遭到封鎖的資源 / 執行目前遭到封鎖的 js。


為了探索這個使用者情境,我們建立了一些簡單的範例網頁,展示我們感興趣的 CSP 違規情形,並探索範例網頁,讓自己熟悉這個程序。以下是一些網頁範例 (開啟示範專案,並開啟「Issues」分頁):

我們透過這個程序,瞭解到來源位置是偵錯 CSP 問題時最重要的資訊。我們也發現,在資源遭到封鎖的情況下,快速找出相關 iframe 和要求也很有幫助,此外,在 DevTools 的「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 產生 DevTools 前端所需的 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 後端產生及傳送這些資料結構,並將其傳送至 DevTools 前端。使用該程式庫,您可以使用下列 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),我們需要找出後端實際提供資訊的位置。幸運的是,CSP 程式碼已設有用於僅報表模式的瓶頸,我們可以將其鉤掛至:ContentSecurityPolicy::ReportViolation 回報問題至 (選用) 報表端點,這個端點可在 CSP HTTP 標頭中設定。我們想要回報的大部分資訊都已可用,因此後端不需要進行重大變更,檢測工具就能正常運作。

步驟 4:儲存並顯示問題

我們也想回報開發人員工具尚未開啟前發生的問題,這點與控制台訊息的處理方式類似,也就是說,我們不會立即將問題回報至前端,而是使用儲存空間,在開發人員工具開啟或關閉時,都會填入問題。只要開啟 DevTools (或連結任何其他 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 問題。

偵錯 Trusted Types 問題

如果沒有合適的開發人員工具,大規模使用 TT 可能會相當困難。

改善主控台列印功能

使用信任物件時,我們會至少顯示與不受信任的對應物件相同數量的資訊。很抱歉,目前在顯示信任物件時,系統不會顯示包裝物件的相關資訊。

這是因為控制台中顯示的值,預設會從對物件呼叫 .valueOf() 取得。不過,在信任類型中,傳回的值並不是那麼實用。我們希望您在呼叫 .toString() 時看到的內容類似於以下內容。為達成這項目標,我們需要修改 V8 和 Blink,以便為信任類型物件引進特殊處理機制。

雖然基於歷史原因,這項自訂處理作業是在 V8 中完成,但這種做法有重大缺點。許多物件都需要自訂顯示,但在 JS 層級的類型相同。由於 V8 是純 JS,因此無法區分與 Web API 相對應的概念,例如信任類型。因此,V8 必須請其嵌入程式 (Blink) 協助區分這兩者。

因此,將該部分程式碼移至 Blink 或任何內嵌程式似乎是合理的選擇。除了公開的問題之外,還有許多其他好處:

  • 每個嵌入者都可以自行產生說明
  • 透過 Blink API 產生說明會更簡單
  • Blink 可存取物件的原始定義。因此,如果我們使用 .toString() 產生說明,.toString() 就不會重新定義。

違規中斷 (在「僅報表」模式中)

目前偵錯 TT 違規的唯一方法,就是在 JS 例外狀況上設定中斷點。由於強制執行的 TT 違規會觸發例外狀況,這項功能可能會有所幫助。不過,在實際情況中,您需要更精細地控管違反 TT 的情況。特別是,我們希望只在發生 TT 違規 (而非其他例外狀況) 時中斷,並在僅報模式下中斷,以及區分不同類型的 TT 違規。

開發人員工具已支援多種中斷點,因此架構可擴充性相當高。如要新增中斷點類型,您必須在後端 (Blink)、CDP 和前端進行變更。我們應該引入新的 CDP 指令,讓我們稱之為 setBreakOnTTViolation。前端會使用這個指令,告訴後端應中斷哪些類型的 TT 違規。後端 (特別是 InspectorDOMDebuggerAgent) 會提供「探針」onTTViolation(),每次發生 TT 違規時都會呼叫。接著,InspectorDOMDebuggerAgent 會檢查該違規事項是否應觸發中斷點,如果是,就會傳送訊息至前端,以便暫停執行作業。

目前進度和後續步驟

自從這裡說明的問題出現以來,「Issues」分頁已進行許多變更:

日後,我們打算使用「問題」分頁顯示更多問題,這樣長遠來說,就能從控制台移除無法讀取的錯誤訊息流程。

下載預覽管道

建議您將 Chrome Canary開發人員版Beta 版設為預設開發人員版瀏覽器。這些預覽管道可讓您存取最新的 DevTools 功能,測試最新的網路平台 API,並在使用者發現問題前,協助您找出網站的問題!

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

請使用下列選項討論新功能、更新或任何與開發人員工具相關的內容。