ブラウザ Telemetry プロキシとコア Web Vitals
Telemetry JavaScript SDK は、秘密 API キーを使用し、信頼できるサーバー コードに属します。そのキーをブラウザ アプリケーションにバンドルしないでください。 Core Web Vitals または制限されたフロントエンド信頼性イベントを収集するには、ホワイトリストに登録された小さなペイロードを独自の同一生成元エンドポイントに送信し、そのエンドポイントがそれを Telemetry に転送できるようにします。
この設計では、資格情報がサーバー側に保持され、アプリケーションに同意、送信元チェック、レート制限、フィールド タイプ、ペイロード サイズ、およびプライバシー ルールを適用するための 1 か所が提供されます。
建築
browser measurement
-> POST /api/browser-telemetry
-> origin, size, rate, and schema checks
-> server-side telemetry-sh client
-> browser_performance_measured table
プロキシは一般的なログ エンドポイントではありません。既知のイベント名と既知のフィールドのみを受け入れます。クライアントが指定したテーブル名や Telemetry API キーは決して受け入れないでください。
ブラウザコントラクトを定義する
Core Web Vitals の場合、メトリクスごとに 1 つのイベントを簡単に検証できます。
type BrowserMetric = {
event_name: "browser_performance_measured";
metric_name: "CLS" | "INP" | "LCP";
metric_value: number;
metric_id: string;
route_template: string;
release: string;
navigation_type: string;
};
次のようなルート テンプレートを使用します。 /projects/:idではありません location.href。クエリ文字列、DOM テキスト、フォーム値、Cookie、認証データ、識別子を含むリファラー、または任意のエラー メッセージを送信しないでください。ランダムなメトリック ID は再送信の重複排除に役立ちますが、クロスサイト ユーザー識別子になるべきではありません。
ブラウザで Web Vitals を収集する
の web-vitals パッケージは現在の Core Web Vitals をレポートします。ポリシーおよび管轄区域によって同意が必要な場合は、同意後に送信します。
import { onCLS, onINP, onLCP, type Metric } from "web-vitals";
function reportMetric(metric: Metric) {
const body = JSON.stringify({
event_name: "browser_performance_measured",
metric_name: metric.name,
metric_value: metric.value,
metric_id: metric.id,
route_template: routeTemplateFor(location.pathname),
release: window.__APP_RELEASE__,
navigation_type: metric.navigationType,
});
if (navigator.sendBeacon) {
navigator.sendBeacon(
"/api/browser-telemetry",
new Blob([body], { type: "application/json" }),
);
return;
}
void fetch("/api/browser-telemetry", {
method: "POST",
headers: { "content-type": "application/json" },
body,
keepalive: true,
credentials: "same-origin",
});
}
onCLS(reportMetric);
onINP(reportMetric);
onLCP(reportMetric);
sendBeacon ページ終了時の小さなベストエフォート型ペイロードに適しています。配信は保証されず、ブラウザ拡張機能によってリクエストがブロックされる可能性があり、ユーザーが送信前にページを閉じる可能性があります。ブラウザーの測定値は、正確な請求や監査台帳ではなく、サンプリングされたエクスペリエンス データとして扱われます。
サーバー上で検証して転送する
エンドポイントは、不明な起源、イベント名、メトリック名、非有限値、過大な本体、および予期しないフィールドを拒否する必要があります。以下の例は境界を示しています。リクエストとレスポンスのプリミティブをサーバー フレームワークに適応させます。
import { Telemetry } from "telemetry-sh";
const telemetry = new Telemetry(process.env.TELEMETRY_API_KEY);
const allowedMetrics = new Set(["CLS", "INP", "LCP"]);
export async function POST(request: Request) {
if (!isAllowedSameOrigin(request)) {
return new Response("forbidden", { status: 403 });
}
const contentLength = Number(request.headers.get("content-length") || 0);
if (contentLength > 4096 || !(await rateLimit(request))) {
return new Response("rejected", { status: 429 });
}
const input = await request.json();
if (
input.event_name !== "browser_performance_measured" ||
!allowedMetrics.has(input.metric_name) ||
!Number.isFinite(input.metric_value) ||
!isAllowedRouteTemplate(input.route_template)
) {
return new Response("invalid event", { status: 400 });
}
await telemetry.log("browser_performance_measured", {
metric_name: input.metric_name,
metric_value: input.metric_value,
metric_id: boundedString(input.metric_id, 80),
route_template: input.route_template,
release: boundedString(input.release, 80),
navigation_type: boundedCategory(input.navigation_type),
});
return new Response(null, { status: 202 });
}
運用環境では、サーバー プロセスごとに 1 回クライアントを初期化し、制限されたアップストリーム タイムアウトを使用し、テレメトリのエラーが返されるかどうかを決定します。 202, 204、または再試行可能な応答。ブラウザーの再試行ループを回避します。ネットワークとセッションの境界による小さなレート制限により悪用を減らすことができますが、イベントに生の IP アドレスを保存しないでください。
セキュリティとプライバシーのチェックリスト
- キープする
TELEMETRY_API_KEYサーバーランタイムのみ。 - エンドポイントを同じオリジンのリクエストと、予想されるメソッドとコンテンツ タイプに制限します。
- JSON を解析する前に、小さな本体制限を適用します。
- ホワイトリストのイベント名、フィールド、カテゴリ、ルート テンプレート、および数値範囲。
- アップストリーム API を呼び出す前のレート制限。
- クロスオリジンコレクションが意図的にレビューされた製品でない限り、寛容な CORS を使用しないでください。
- 収集前に同意およびオプトアウトのルールを適用します。
- 任意の識別子の保持および削除の動作を定義します。
- 拒否されたペイロードをコピーせずに、拒否されたリクエストやレート制限されたリクエストを監視します。
CSRF 防御は、エンドポイントが認証情報を受け入れる場合、またはユーザーにリンクされた状態を変更する場合にも重要です。匿名の同一オリジン測定エンドポイントの場合、オリジン検証、厳密なコンテンツ タイプ、およびユーザー固有ではないペイロードが適切な境界となる可能性があります。その選択をアプリケーションのセキュリティ モデルで確認してください。
データを検証する
最初に非実稼働環境にデプロイします。次のことを確認します。
- ブラウザ バンドルには Telemetry キーが含まれていません。
- 不明なイベント名、余分なフィールド、生の URL、および大きすぎる本文は拒否されます。
- 有効な CLS、INP、および LCP イベントは数値とともに到着します。
- 収集リクエストがブロックまたは失敗しても、ナビゲーションには影響しません。
- リリースとルートの値はグループ化できるほど安定しています。
- スパースルートはノイズの多いアラートには使用されません。
を使用します。 ルートおよびリリースレシピ別のコアウェブバイタル 測定値の横にサンプル数を保存します。続けて SQL によるフロントエンド信頼性モニタリング、 JavaScript SDK ガイド、そして 機密データの編集.