Reporting API を使用してウェブ アプリケーションをモニタリングする

Reporting API を使用して、セキュリティ違反や非推奨の API 呼び出しなどをモニタリングします。

エラーの中には、本番環境でのみ発生するものもあります。実際のユーザー、実際のネットワーク、実際のデバイスによってゲームが変わるため、ローカルや開発中に確認することはできません。Reporting API は、セキュリティ違反や、サイト全体で非推奨になった API 呼び出しや間もなく非推奨になる API 呼び出しなど、こうしたエラーの一部を検出し、指定したエンドポイントに送信します。

HTTP ヘッダーを使用してモニタリングする内容を宣言でき、ブラウザによって動作します。

Reporting API を設定すると、ユーザーがこのようなエラーに遭遇したときに、そのことを把握して修正できるようになります。

この記事では、この API でできることと、その使用方法について説明します。それでは詳しく見ていきましょう。

概要

レポートの生成からデベロッパーによるレポートへのアクセスまでの手順をまとめた図
レポートの生成と送信の仕組み。

サイト site.example に Content-Security-Policy と Document-Policy があるとします。これらの機能が何をするものかわからない場合は、それでも、この例を理解することはできます。

これらのポリシーが違反されたタイミングを把握するため、また、コードベースで使用されている可能性のある非推奨の API や、まもなく非推奨になる 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 違反レポート、非推奨レポートを生成します。

ブラウザは、最大 1 分の遅延の後に、この違反タイプ用に構成されたエンドポイントにレポートを送信します。レポートは、ブラウザ自体によって(サーバーやサイトではなく)アウトオブバンドで送信されます。

エンドポイントはこれらのレポートを受信します。

これらのエンドポイントのレポートにアクセスして、何が問題だったかをモニタリングできるようになりました。これで、ユーザーに影響している問題のトラブルシューティングを開始する準備が整いました。

サンプル レポート

{
  "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 のみ) ページの 1 つに Content-Security-Policy(CSP)を設定しましたが、そのページで CSP で許可されていないスクリプトを読み込もうとしています。
COOP 違反 ページに Cross-Origin-Opener-Policy を設定しましたが、クロスオリジン ウィンドウがドキュメントと直接やり取りしようとしています。
COEP 違反 ページに Cross-Origin-Embedder-Policy を設定しましたが、ドキュメントにはクロスオリジン ドキュメントによる読み込みをオプトインしていないクロスオリジン 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"