使用 Reporting API 監控網頁應用程式

使用 Reporting API 監控安全性違規事項、已淘汰的 API 呼叫等。

Maud Nalpas
Maud Nalpas

某些錯誤只會在實際工作環境中發生。您不會在本機或開發期間看到這些項目,因為「實際使用者」、「實際網路」和「實際裝置」會改變遊戲。Reporting API 可協助擷取部分這類錯誤 (例如安全性違規事項或已淘汰和即將淘汰的 API 呼叫),並將這些呼叫傳送到您指定的端點。

可讓您宣告要透過 HTTP 標頭監控的內容,並由瀏覽器執行。

設定 Reporting API 可讓您安心,當使用者遇到這類錯誤時,我們會告訴您,以便修正錯誤。

這篇文章說明這個 API 的功能和使用方式。那就繼續下一步吧!

示範模式和程式碼

瞭解 Reporting API 從 2021 年 10 月從 Chrome 96 以上版本 (Chrome Beta 版或 Canary 版) 的實際運作情形。

總覽

從產生報表到開發人員報表存取權的流程摘要圖表
報表的產生及傳送方式。

假設您的網站「site.example」設有內容安全政策和 Document-政策。不知道這有哪些功能嗎?沒關係 您還是能瞭解此範例

您決定監控網站,瞭解違反這些政策的時間,但也請留意程式碼集可能正在使用的已淘汰或即將淘汰的 API。

如要這麼做,請設定 Reporting-Endpoints 標頭,並在需要時透過政策中的 report-to 指令對應這些端點名稱。

Reporting-Endpoints: main-endpoint="https://reports.example/main", default="https://reports.example/default"
# Content-Security-Policy violations and Document-Policy violations
# will be sent to main-endpoint
Content-Security-Policy: script-src 'self'; object-src 'none'; report-to main-endpoint;
Document-Policy: document-write=?0; report-to=main-endpoint;
# Deprecation reports don't need an explicit endpoint because
# these reports are always sent to the `default` endpoint

發生意外事件,導致部分使用者違反這些政策。

違規示例

index.html

<script src="script.js"></script>
<!-- CSP VIOLATION: Try to load a script that's forbidden as per the Content-Security-Policy -->
<script src="https://example.com/script.js"></script>

script.js,由 index.html 載入

// DOCUMENT-POLICY VIOLATION: Attempt to use document.write despite the document policy
try {
  document.write('<h1>hi</h1>');
} catch (e) {
  console.log(e);
}
// DEPRECATION: Call a deprecated API
const webkitStorageInfo = window.webkitStorageInfo;

瀏覽器會產生 CSP 違規報告、文件違反政策報告,以及擷取這些問題的淘汰報告。

瀏覽器傳送報表到針對此違規類型設定的端點,延遲時間最長為一分鐘。報表是由瀏覽器本身 (而非伺服器或您的網站) 傳送的頻外傳送。

接收這些報告的端點。

您現在可以存取這些端點的報告,監控問題所在。您隨時可以開始排解影響使用者的問題。

範例報表

{
  "age": 2,
  "body": {
    "blockedURL": "https://site2.example/script.js",
    "disposition": "enforce",
    "documentURL": "https://site.example",
    "effectiveDirective": "script-src-elem",
    "originalPolicy": "script-src 'self'; object-src 'none'; report-to main-endpoint;",
    "referrer": "https://site.example",
    "sample": "",
    "statusCode": 200
  },
  "type": "csp-violation",
  "url": "https://site.example",
  "user_agent": "Mozilla/5.0... Chrome/92.0.4504.0"
}

用途和報表類型

您可以調整 Reporting API 設定,監控整個網站中發生的多種有趣的警告或問題:

報表類型 需要產生報表的情況
違反 CSP (僅限第 3 級) 您已在其中一個網頁上設定 Content-Security-Policy (CSP),但該網頁嘗試載入的指令碼未受 CSP 規範。
違反 COOP 政策 您已在頁面上設定 Cross-Origin-Opener-Policy,但某個跨來源視窗正嘗試直接與文件互動。
違反 COEP 您已在頁面上設定 Cross-Origin-Embedder-Policy,但文件包含的跨來源 iframe 並未選擇由跨來源文件載入。
違反文件政策 網頁含有禁止使用 document.write 的文件政策,但指令碼嘗試呼叫 document.write
違反權限政策 網頁設有禁止使用麥克風的權限政策,以及要求音訊輸入的指令碼。
淘汰警告 該網頁使用的 API 已淘汰或即將淘汰,必須直接呼叫或透過頂層第三方指令碼進行呼叫。
幹預 網頁嘗試執行的功能,是瀏覽器基於安全性、效能或使用者體驗等因素,判定不得遵循的行為。Chrome 範例:網頁會在速度緩慢的網路中使用 document.write,或是在使用者尚未互動的跨來源頁框中呼叫 navigator.vibrate
意外事故 瀏覽器在開啟您的網站時當機,

報表

報表長什麼樣子?

瀏覽器會將報表傳送至您設定的端點。它會傳送看起來像這樣的要求:

POST
Content-Type: application/reports+json

這類要求的酬載則是一份報表清單。

報表清單範例

[
  {
    "age": 420,
    "body": {
      "columnNumber": 12,
      "disposition": "enforce",
      "lineNumber": 11,
      "message": "Document policy violation: document-write is not allowed in this document.",
      "policyId": "document-write",
      "sourceFile": "https://site.example/script.js"
    },
    "type": "document-policy-violation",
    "url": "https://site.example/",
    "user_agent": "Mozilla/5.0... Chrome/92.0.4504.0"
  },
  {
    "age": 510,
    "body": {
      "blockedURL": "https://site.example/img.jpg",
      "destination": "image",
      "disposition": "enforce",
      "type": "corp"
    },
    "type": "coep",
    "url": "https://dummy.example/",
    "user_agent": "Mozilla/5.0... Chrome/92.0.4504.0"
  }
]

以下是您可以在這些報表中查看的資料:

欄位 說明
age 報表時間戳記和目前時間之間的毫秒數。
body 實際的報表資料,已序列化為 JSON 字串。報表的 body 包含的欄位取決於報表的 type⚠️ 不同類型的報表擁有不同的主體。 如要瞭解每種報表類型的確切內文,請參閱示範報表端點 ,並按照操作說明產生範例報表。
type 報表類型,例如 csp-violationcoep
url 產生報表的文件或工作人員地址。使用者名稱、密碼和片段等機密資料會從這個網址中移除
user_agent 報表產生來源要求的 User-Agent 標頭。

認證報表

報表端點與產生報表的網頁相同,會在包含報表的要求中收到憑證 (Cookie)。

憑證可提供實用的報表相關額外背景資訊。例如,特定使用者的帳戶是否持續觸發錯誤,或者是使用者在其他網頁上採取的特定動作順序,在此頁面上觸發報表。

瀏覽器傳送報表的時機及方式為何?

報表會透過網站外模式傳送:將報表傳送至已設定的端點時,瀏覽器會進行控制選項。沒有任何方法可控制瀏覽器傳送報表的時間;能夠擷取、將報表排入佇列,並在適當的時間自動傳送。

也就是說,使用 Reporting API 時幾乎不用擔心效能問題,

報表會延遲傳送 (最多 1 分鐘),以提高分批傳送報表的機率。 這可以節省頻寬以尊重使用者的網路連線,這對行動裝置來說特別重要。如果瀏覽器忙於處理高優先順序的工作,或是使用者正在使用速度緩慢且/或擁擠的網路,瀏覽器也可能會延遲傳遞。

第三方和第一方問題

因違規或淘汰問題產生的報表,會傳送至您的網頁所設定的端點。這包括在您網頁上執行的第三方指令碼所做出的違規行為。

在網頁中內嵌的跨來源 iframe 中發生的違規事項或淘汰事件「不會」回報至端點 (至少不會回報)。iframe 可以設定自己的報表,甚至向網站回報 (也就是第一方的報表服務,但交由頁框式網站負責)。另請注意,大部分的報表只會在違反網頁的政策,且網頁的政策和 iframe 的政策不同時產生。

淘汰範例

如果您的網頁設定了 Reporting-Endpoint 標頭,則網頁上執行的第三方指令碼呼叫的已淘汰 API 將回報至您的端點。網頁中內嵌 iframe 呼叫的已淘汰 API,將不會回報至端點。只有在 iframe 伺服器設定「報告端點」的情況下,系統才會產生淘汰報表,且系統會將這份報表傳送到該 iframe 伺服器設定的端點。
如果網頁上設定 Reporting-Endpoint 標頭:系統會向在網頁上執行的第三方指令碼呼叫已淘汰的 API。網頁中內嵌 iframe 呼叫的已淘汰 API,將不會回報至端點。只有在 iframe 伺服器設定「報表端點」的情況下,系統才會產生淘汰報表,且系統會將這份報表傳送到該 iframe 伺服器設定的端點。

瀏覽器支援

下表總結了支援 Reporting-Endpoints 標頭的 Reporting API v1 瀏覽器支援。Reporting API v0 (Report-To 標頭) 的瀏覽器支援相同,但有一個報表類型除外:新版 Reporting API 不支援網路錯誤記錄。詳情請參閱遷移指南

報表類型 Chrome Chrome iOS 版 Safari Firefox Edge
違反 CSP (僅限第 3 級)* ✔ 是 ✔ 是 ✔ 是 ✘ 否 ✔ 是
網路錯誤記錄 ✘ 否 ✘ 否 ✘ 否 ✘ 否 ✘ 否
違反 COOP/COEP 規定 ✔ 是 ✘ 否 ✔ 是 ✘ 否 ✔ 是
所有其他類型:違反文件政策、淘汰、介入、當機 ✔ 是 ✘ 否 ✘ 否 ✘ 否 ✔ 是

這個表格只列出對 report-to 支援及新 Reporting-Endpoints 標頭的摘要。如要遷移至 Reporting-Endpoints,請參閱 CSP 報告遷移提示

使用 Reporting API

決定報表寄送位置

您可以採用兩種方法:

  • 將報表傳送至現有的報表收集器服務。
  • 將報表傳送給您自行建構和經營的報表收集器。

方法 1:使用現有的報表收集器服務

報表收集器服務的幾個範例如下:

如果您知道其他解決方案,請提出問題告訴我們,我們會更新這篇文章!

除了價格以外,選擇報表收集器時,請將以下要點納入考量:🧐?

  • 這個收集器是否支援所有報表類型?例如,並非所有報告端點解決方案都支援 COOP/COEP 報告。
  • 您是否願意與第三方報表收集器分享任何應用程式網址? 即使瀏覽器會去除這些網址中的機密資訊,機密資訊仍會透過這種方式外洩。如果這個結果對應用程式而言風險過高,請操作自己的回報端點。

方法 2:建立及操作自己的報表收集器

建立自己的伺服器來接收報表可不簡單。如要開始使用,您可以先透過分支 建立輕量的樣板它以 Express 為基礎,可以接收及顯示報表。

  1. 前往樣板報表收集器

  2. 按一下「Remix to Edit」,讓專案可供編輯。

  3. 您現在可以取得本機副本了!您可以依據個人用途自訂該範本。

如果不是使用樣板,而是從頭開始建構自己的伺服器:

  • 檢查 Content-Typeapplication/reports+jsonPOST 要求,以辨識瀏覽器傳送至端點的報表要求。
  • 如果端點與網站的來源不同,請確認端點支援 CORS 預檢要求

方法 3:合併選項 1 和 2

您可能想讓特定供應商處理某些類型的報表,但有些供應商也想採用內部解決方案。

在此情況下,請按照下列方式設定多個端點:

Reporting-Endpoints: endpoint-1="https://reports-collector.example", endpoint-2="https://my-custom-endpoint.example"

設定 Reporting-Endpoints 標頭

設定 Reporting-Endpoints 回應標頭。其值必須是一或多個以半形逗號分隔的鍵/值組合:

Reporting-Endpoints: main-endpoint="https://reports.example/main", default="https://reports.example/default"

如果您是從舊版 Reporting API 遷移至新版 Reporting API,建議您「同時」設定 Reporting-EndpointsReport-To。詳情請參閱遷移指南。具體來說,如果只有透過 report-uri 指令回報 Content-Security-Policy 違規事項,請參閱 CSP 回報遷移步驟

Reporting-Endpoints: main-endpoint="https://reports.example/main", default="https://reports.example/default"
Report-To: ...

鍵 (端點名稱)

每個鍵可以是您選擇的名稱,例如 main-endpointendpoint-1。您可以決定為不同的報表類型 (例如 my-coop-endpointmy-csp-endpoint) 設定不同的命名端點。透過此設定,您就能根據類型將報表轉送至不同的端點。

如要接收介入淘汰和/或當機報表,請將端點設為 default

如果 Reporting-Endpoints 標頭未定義 default 端點,系統不會傳送這類報表 (但系統會產生這類報表)。

值 (網址)

每個值都是您選擇的網址,報表將傳送至此網址。此處設定的網址取決於您在步驟 1 中的決定。

端點網址:

示例

Reporting-Endpoints: my-coop-endpoint="https://reports.example/coop", my-csp-endpoint="https://reports.example/csp", default="https://reports.example/default"

接著,您可以在適當的政策中使用每個已命名的端點,或在所有政策中使用單一端點。

哪裡可以設定標頭?

在新的 Reporting API (本文提到的 API) 中,報表範圍僅限「文件」,也就是說,對於特定來源來說,site.example/page1site.example/page2 等不同文件都可以將報表傳送至不同的端點。

如要接收網站上任何頁面的違規或淘汰報告,請將所有回應的標頭設為中介軟體。

以下是 Express 的範例:

const REPORTING_ENDPOINT_BASE = 'https://report.example';
const REPORTING_ENDPOINT_MAIN = `${REPORTING_ENDPOINT_BASE}/main`;
const REPORTING_ENDPOINT_DEFAULT = `${REPORTING_ENDPOINT_BASE}/default`;

app.use(function (request, response, next) {
  // Set up the Reporting API
  response.set(
    'Reporting-Endpoints',
    `main-endpoint="${REPORTING_ENDPOINT_MAIN}", default="${REPORTING_ENDPOINT_DEFAULT}"`,
  );
  next();
});

編輯政策

設定 Reporting-Endpoints 標頭後,請在您要接收違規報告的每個政策標頭中加入 report-to 指令。report-to 的值必須是您已設定的其中一個已命名端點。

您可以將多個端點用於多項政策,或跨政策使用不同的端點。

根據各項政策,回報為目標的值應為您已設定的其中一個已命名端點。

使用淘汰介入當機報表時,不需要 report-to。這些報告並未繫結至任何政策。只要在設定 default 端點並傳送到這個 default 端點,系統就會產生這些憑證。

範例

# Content-Security-Policy violations and Document-Policy violations
# will be sent to main-endpoint
Content-Security-Policy: script-src 'self'; object-src 'none'; report-to main-endpoint;
Document-Policy: document-write=?0;report-to=main-endpoint;
# Deprecation reports don't need an explicit endpoint because
# these reports are always sent to the default endpoint

程式碼範例

以下為使用 Express 的 Node 伺服器範例,並匯總了本文討論的所有部分,方便您瞭解相關情況。說明如何設定多種不同報表類型的報表及顯示結果。

對報表設定進行偵錯

刻意產生報告

設定 Reporting API 時,您可能需要刻意違反政策,才能檢查報表是否如預期產生及傳送。如要查看違反政策的範例程式碼,以及會產生所有類型報表的惡意行為,請參考示範

節省時間

報表可能會延遲傳送,大約一分鐘,也就是偵錯時的「長」時間。🎁? 幸運的是,在 Chrome 中偵錯時,你可以使用 --short-reporting-delay 旗標在報告產生後立即收到報告。

在終端機中執行下列指令,即可啟用此標記:

YOUR_PATH/TO/EXECUTABLE/Chrome --short-reporting-delay

使用開發人員工具

在 Chrome 中,使用開發人員工具查看已傳送或即將傳送的報告。

自 2021 年 10 月起,這項功能仍處於實驗階段。如要使用,請按照下列步驟操作:

  1. 使用 Chrome 96 以上版本 (如要檢查,請在瀏覽器中輸入 chrome://version)
  2. 在 Chrome 的網址列中輸入或貼上 chrome://flags/#enable-experimental-web-platform-features
  3. 按一下「已啟用」
  4. 重新啟動瀏覽器。
  5. 開啟 Chrome 開發人員工具。
  6. 在 Chrome 開發人員工具中開啟「設定」。在「實驗」下方,點選「在應用程式面板中啟用 Reporting API 面板」
  7. 重新載入開發人員工具。
  8. 重新載入網頁。透過網頁開發人員工具開啟的報表會顯示在 Chrome 開發人員工具的「Application」面板中,位於「Reporting API」下方。
列出報告的開發人員工具螢幕截圖
Chrome 開發人員工具會顯示在網頁上產生的報表及其狀態。

報表狀態

「狀態」欄會顯示報表是否已成功傳送。

狀態 說明
Success 瀏覽器已傳送報表,且端點以成功代碼 (200 或其他成功回應代碼 2xx) 回覆。
Pending 瀏覽器正在嘗試傳送報表。
Queued 報表已產生,瀏覽器目前並未嘗試傳送。下列兩種情況的報表會顯示為 Queued
  • 這類報告是全新功能,瀏覽器正在等待我們確認是否收到更多報表,然後再嘗試傳送。
  • 此報表並非新報表;瀏覽器嘗試傳送此報表但失敗,正在等待重試。
MarkedForRemoval 在重試一段時間 (Queued) 後,瀏覽器已停止嘗試傳送報表,很快就會從報表清單中移除要傳送的報表。

無論報表是否已成功傳送,我們很快就會移除。

疑難排解

報表是否未如預期產生或未如預期將報表傳送至您的端點? 下列幾個提示可用於排解這個問題。

無法產生報表

開發人員工具中顯示的報表已正確產生。 如果所需報表「並未」顯示在這份清單中:

  • 請查看政策中的「report-to」。如果設定有誤,系統就不會產生報表。如要修正這個問題,請前往「編輯政策」。另一個疑難排解方法是查看 Chrome 的開發人員工具控制台:如果控制台中彈出錯誤,顯示您預期的違規行為,這表示您的政策可能設定正確。
  • 請注意,這份清單只會顯示針對以文件開發工具開啟的報表,例如:如果您的網站 site1.example 嵌入的 iframe site2.example 違反相關政策,因而產生報告,您必須先在專屬視窗中開啟 iframe,並開啟該視窗的開發人員工具,才能在開發人員工具中顯示這份報表。

報表已產生,但並未傳送或未收到

如果您可以在開發人員工具中查看報表,但端點未收到該報告,該怎麼辦?

  • 務必使用短暫延遲。您看不到報表的原因可能是報表尚未傳送!
  • 請檢查您的 Reporting-Endpoints 標頭設定。如果有問題,系統就不會傳送正確產生的報表。在開發人員工具中,報表的狀態將維持在 Queued (可能會跳到 Pending,然後在嘗試提交時快速返回 Queued)。可能造成此情況的常見錯誤:

  • 已使用端點,但尚未設定。示例:

程式碼有誤
 Document-Policy: document-write=?0;report-to=endpoint-1;
 Reporting-Endpoints: default="https://reports.example/default"

文件違規報告應傳送至 endpoint-1,但這個端點名稱未在 Reporting-Endpoints 中設定。

  • 缺少「default」端點。部分報表類型 (例如淘汰和乾預報表) 只會傳送至名為 default 的端點。詳情請參閱設定 Reporting-Endpoint 標頭

  • 找出政策標頭語法中的問題,例如缺少引號。瞭解詳情

  • 請檢查端點是否可以處理傳入要求。

    • 請確認您的端點支援 CORS 預檢要求。否則無法接收報表。

    • 測試端點的行為。如此一來,與其手動產生報表,您可以向瀏覽器傳送模擬瀏覽器的要求,方法是將「看起來」瀏覽器傳送的內容「看起來」,藉此模擬瀏覽器。執行以下指令:

    curl --header "Content-Type: application/reports+json" \
      --request POST \
      --data '[{"age":420,"body":{"columnNumber":12,"disposition":"enforce","lineNumber":11,"message":"Document policy violation: document-write is not allowed in this document.","policyId":"document-write","sourceFile":"https://dummy.example/script.js"},"type":"document-policy-violation","url":"https://dummy.example/","user_agent":"xxx"},{"age":510,"body":{"blockedURL":"https://dummy.example/img.jpg","destination":"image","disposition":"enforce","type":"corp"},"type":"coep","url":"https://dummy.example/","user_agent":"xxx"}]' \
      YOUR_ENDPOINT
    

    您的端點應以成功代碼 (200 或其他成功回應代碼 2xx) 回應。如果仍未成功,表示其設定有問題。

僅報表

-Report-Only 政策標頭和 Reporting-Endpoints 會搭配運作。

違反這些政策時,系統會在 Reporting-Endpoints 內設定端點,並在 Content-Security-PolicyCross-Origin-Embedder-PolicyCross-Origin-Opener-Policyreport-to 欄位中指定端點。

您也可以在 Content-Security-Policy-Report-OnlyCross-Origin-Embedder-Policy-Report-OnlyCross-Origin-Opener-Policy-Report-Onlyreport-to 欄位中指定 Reporting-Endpoints 中設定的端點。違反這些政策時,他們也會收到相關報告。

雖然系統會在這兩種情況下傳送報表,但 -Report-Only 標頭不會強制執行政策:不會有任何破壞或實際遭到封鎖,但您會收到「實際」毀損或遭到封鎖的報告。

ReportingObserver

ReportingObserver JavaScript API 可協助您觀察用戶端警告。

ReportingObserverReporting-Endpoints 標頭產生的報表樣式相同,但用途稍有不同。

下列情況請使用 ReportingObserver

  • 只想監控淘汰情形和/或瀏覽器介入措施。 ReportingObserver 會顯示用戶端警告,例如淘汰和瀏覽器幹預,但與 Reporting-Endpoints 不同,它不會擷取任何其他類型的報表,例如 CSP 或 COOP/COEP。
  • 您必須即時回應這些違規行為。ReportingObserver 可讓您針對違規事件附加回呼
  • 您想透過自訂回呼,為報表附加其他資訊,以便偵錯。

另一個差別在於,ReportingObserver 只能設定在用戶端:即使您無法控管伺服器端標頭,且無法設定 Reporting-Endpoints,還是可以使用此方法。

其他資訊

主頁橫幅由 Nine Koepfer / @enka80Unsplash 網站上編輯。感謝 Ian Clelland、Eiji Kitamura、Milica Mihajlija 針對這篇文章的評論和建議。