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

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

Maud Nalpas
Maud Nalpas

有些錯誤只會在正式版中發生。您不會在本地或開發期間看到這些問題,因為實際使用者實際網路實際裝置會改變遊戲。Reporting API 可協助您找出網站上的一些錯誤,例如安全性違規事項,或是已淘汰及即將淘汰的 API 呼叫,並將這些錯誤傳輸至您指定的端點。

您可以使用 HTTP 標頭宣告要監控的內容,並由瀏覽器運作。

設定 Reporting API 後,當使用者遇到這類錯誤時,您就會收到通知,以便修正問題。

這篇文章將說明這項 API 的用途和使用方式。讓我們深入瞭解!

總覽

圖表:總結下方步驟,從產生報表到開發人員存取報表
報表的產生和傳送方式。

假設您的網站 (site.example) 具有 Content-Security-Policy 和 Document-Policy。不確定這些功能有什麼用途嗎?沒關係,你還是可以瞭解這個範例。

您決定監控網站,不僅是為了瞭解何時違反這些政策,也是為了留意程式碼集可能使用的已淘汰或即將淘汰 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 違規報告、Document-Policy 違規報告和淘汰報告,記錄這些問題。

瀏覽器會在短暫延遲 (最多一分鐘) 後,將報表傳送到為這類違規事項設定的端點。報表是由瀏覽器本身「頻外」傳送 (不是由伺服器或網站傳送)。

端點會接收這些報表。

您現在可以存取這些端點的報表,並監控發生錯誤的原因。現在可以開始排解影響使用者的問題。

範例報表

{
  "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,且該 iframe 未選擇由跨來源文件載入。
違反文件政策 網頁的檔案政策禁止使用 document.write,但指令碼嘗試呼叫 document.write
違反權限政策 網頁的權限政策禁止使用麥克風,但有要求音訊輸入的指令碼。
淘汰警告 網頁使用已淘汰或即將淘汰的 API,並直接呼叫該 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 時,幾乎不必擔心效能問題。

報表會延遲傳送 (最多一分鐘),以提高分批傳送報表的機率。這樣做可節省頻寬,避免耗用使用者網路連線的流量,這對行動裝置尤其重要。如果瀏覽器忙於處理優先順序較高的工作,或是使用者當時的網路速度緩慢或壅塞,瀏覽器也可能會延遲傳送通知。

第三方和第一方問題

如果網頁發生違規或淘汰情形,系統會產生報表,並傳送至您設定的端點。包括網頁上執行的第三方指令碼違規行為。

如果網頁中嵌入的跨來源 iframe 發生違規或淘汰情形,系統不會 (至少預設不會) 向端點回報。iframe 可以設定自己的報表,甚至向網站 (也就是第一方) 的報表服務回報,但這取決於框架網站。此外,請注意,只有在網頁違反政策時,系統才會產生大部分的報表,且網頁政策與 iframe 政策不同。

已淘汰的範例

如果網頁已設定 Reporting-Endpoints 標頭,網頁上執行的第三方指令碼呼叫的已淘汰 API,就會回報至您的端點。系統不會向端點回報網頁內嵌 iframe 呼叫的已淘汰 API。只有在 iframe 伺服器已設定 Reporting-Endpoints 時,系統才會產生淘汰報表,並將這份報表傳送至 iframe 伺服器設定的端點。
如果網頁上已設定 Reporting-Endpoints 標頭:網頁上執行的第三方指令碼呼叫的已淘汰 API,會回報給您的端點。如果網頁內嵌的 iframe 呼叫已淘汰的 API,系統不會向端點回報。只有在 iframe 伺服器已設定 Reporting-Endpoints 時,系統才會產生淘汰報表,並將這份報表傳送至 iframe 伺服器設定的端點。

瀏覽器支援

下表彙整了瀏覽器對 Reporting API v1 的支援情況,也就是使用 Reporting-Endpoints 標頭的情況。除了「網路錯誤記錄」報表類型外,瀏覽器對 Reporting API v0 (Report-To 標頭) 的支援程度相同。新版 Reporting API 不支援「網路錯誤記錄」報表類型。詳情請參閱遷移指南

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

下表僅摘要說明新版 Reporting-Endpoints 標頭對 report-to 的支援。如要遷移至 Reporting-Endpoints,請參閱 CSP 報表遷移提示

使用 Reporting API

決定報表的傳送目的地

方法有以下兩種:

  • 將報表傳送至現有的報表收集器服務。
  • 將報表傳送至您自行建構及運作的報表收集器。

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

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

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

除了價格,選取報表收集器時,請考慮下列幾點:🧐

  • 這個收集器是否支援所有報表類型?舉例來說,並非所有報表端點解決方案都支援 COOP/COEP 報表。
  • 您是否願意與第三方報表收集器分享應用程式的網址?即使瀏覽器會從這些網址中移除私密資訊,仍可能因此洩漏私密資訊。如果這對您的應用程式來說風險太高,請自行運作回報端點。

方法 2:自行建構及運作報表收集器

自行建構接收報表的伺服器並非易事。如要開始使用,請分叉我們的輕量樣板。這項工具以 Express 建構而成,可接收及顯示報表。

自行建構報表收集器時,請注意下列事項:

  • 檢查是否有 POST 要求,並使用 Content-Type 識別瀏覽器傳送至端點的報表要求。application/reports+json
  • 如果端點與網站位於不同來源,請確保端點支援 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 中,報表範圍限定為文件。也就是說,對於特定來源,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 值都應是您設定的具名端點之一。

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

偵錯報表設定

有目的地產生報表

設定 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 開發人員工具的「應用程式」面板中,位於「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"

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

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

  • 檢查政策標頭語法是否有問題,例如缺少引號。查看詳細資料

  • 確認端點可以處理傳入的要求。

    • 請確認端點支援 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-Policy 欄位中指定的端點。report-to

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

無論是哪種情況,系統都會傳送報表,但 -Report-Only 標頭不會強制執行政策:不會有任何內容中斷或遭到封鎖,但您會收到報表,瞭解哪些內容可能會中斷或遭到封鎖。

ReportingObserver

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

ReportingObserverReporting-Endpoints 標頭產生的報表看起來相同,但適用的用途略有不同。

在下列情況使用 ReportingObserver

  • 您只想監控淘汰項目或瀏覽器介入措施。ReportingObserver 會顯示用戶端警告,例如淘汰項目和瀏覽器介入措施,但與 Reporting-Endpoints 不同,不會擷取任何其他類型的報表,例如 CSP 或 COOP/COEP 違規事項。
  • 您必須即時處理這些違規事項。ReportingObserver 可讓您將回呼附加至違規事件。
  • 您想使用自訂回呼,在報表中附加額外資訊,協助進行偵錯。

另一個差異是 ReportingObserver 只能在用戶端設定:即使您無法控管伺服器端標頭,也無法設定 Reporting-Endpoints,仍可使用 ReportingObserver

延伸閱讀

主頁橫幅:Nine Koepfer / @enka80 發表於 Unsplash,已編輯。感謝 Ian Clelland、北村英二和 Milica Mihajlija 審查這份文件並提供建議。