Как отслеживать показатели веб-приложений с помощью Reporting API

Используйте Reporting API, чтобы отслеживать нарушения безопасности, устаревшие вызовы API и многое другое.

Некоторые ошибки возникают только в рабочей среде. Вы не увидите их локально или во время разработки, потому что реальные пользователи, реальные сети и реальные устройства меняют игру. 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 из разных источников, которое не разрешает загрузку документов из разных источников.
Нарушение правил в отношении документов Правила в отношении документов запрещают использовать 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-violation или coep.
url Адрес документа или обработчика, из которого был создан отчет. Конфиденциальные данные, такие как имя пользователя, пароль и фрагмент, удаляются из этого URL.
user_agent Заголовок User-Agent запроса, на основе которого был создан отчет.

Отчеты с учетными данными

Конечные точки отчетов, у которых тот же источник, что и у страницы, создающей отчет, получают учетные данные (файлы cookie) в запросах, содержащих отчеты.

Учетные данные могут предоставить полезный дополнительный контекст об отчете, например о том, постоянно ли аккаунт определенного пользователя вызывает ошибки или определенная последовательность действий, предпринятых на других страницах, вызывает отчет на этой странице.

Когда и как браузер отправляет отчеты?

Отчеты доставляются внеполосно с вашего сайта: браузер контролирует, когда они отправляются на настроенные конечные точки. Также нет возможности контролировать, когда браузер отправляет отчеты; он фиксирует, ставит в очередь и отправляет их автоматически в подходящее время.

Это означает, что при использовании Reporting API практически не возникает проблем с производительностью.

Отчеты отправляются с задержкой до минуты, чтобы повысить вероятность отправки пакетами. Это позволяет экономить трафик, что особенно важно для мобильных устройств. Браузер также может отложить доставку, если он занят обработкой более приоритетной задачи или если пользователь в этот момент находится в медленной или перегруженной сети.

Проблемы с собственными и сторонними файлами cookie

Отчеты, созданные из-за нарушений или устаревания, происходящих на вашей странице, будут отправляться в настроенные вами конечные точки. в том числе сторонними скриптами, которые выполняются на ваших страницах.

Нарушения или прекращение поддержки, которые произошли в междоменном iframe, встроенном в вашу страницу, не будут передаваться в ваши конечные точки (по крайней мере, по умолчанию). В iframe можно настроить собственную систему отчетности и даже отправлять данные в сервис отчетности вашего сайта (то есть стороннего сайта), но это зависит от сайта, который показывается во фрейме. Также обратите внимание, что большинство отчетов создается только в случае нарушения правил страницы, а правила страницы и правила iframe различаются.

Пример с устаревшими функциями

Если на вашей странице настроен заголовок Reporting-Endpoints, то вызовы устаревших API сторонними скриптами, выполняемыми на вашей странице, будут передаваться в вашу конечную точку. Если устаревший API вызывается из окна iframe, встроенного в вашу страницу, то отчет об этом не будет отправлен на вашу конечную точку. Отчет о прекращении поддержки будет создан, только если на сервере iframe настроены конечные точки Reporting-Endpoints. Отчет будет отправлен на конечную точку, настроенную на сервере iframe.
Если на вашей странице настроен заголовок Reporting-Endpoints, то в вашу конечную точку будут отправляться отчеты об устаревших API, вызываемых сторонними скриптами, которые выполняются на вашей странице. Если устаревший вызов API выполняется из окна iframe, встроенного в вашу страницу, то отчеты об этом не будут отправляться на вашу конечную точку. Отчет о прекращении поддержки будет создан, только если на сервере iframe настроены конечные точки Reporting-Endpoints. Отчет будет отправлен на конечную точку, настроенную на сервере iframe.

Поддержка браузеров

В таблице ниже указано, какие браузеры поддерживают Reporting API версии 1, то есть заголовок Reporting-Endpoints. Поддержка 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.
  • Вы согласны предоставить URL вашего приложения стороннему сервису сбора жалоб? Даже если браузер удаляет конфиденциальную информацию из этих URL, она может быть раскрыта. Если это кажется вам слишком рискованным, используйте собственную конечную точку для отправки отчетов.

Вариант 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-Endpoints и Report-To. Подробную информацию об этом вы найдете в руководстве по переходу. В частности, если вы используете отчеты о нарушениях Content-Security-Policy с помощью директивы report-uri, ознакомьтесь с инструкциями по переносу для отчетов CSP.

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

Ключи (названия конечных точек)

Каждый ключ может иметь любое название, например main-endpoint или endpoint-1. Вы можете задать разные именованные конечные точки для разных типов отчетов, например my-coop-endpoint и my-csp-endpoint. Это позволяет направлять отчеты в разные конечные точки в зависимости от их типа.

Если вы хотите получать отчеты о вмешательстве, прекращении поддержки, сбоях или их комбинации, задайте конечную точку с названием default.

Если в заголовке Reporting-Endpoints не определена конечная точка default, отчеты этого типа не будут отправляться (хотя они будут создаваться).

Значения (URL)

Каждое значение – это URL, на который будут отправляться отчеты. URL, который нужно указать, зависит от того, что вы решили на шаге 1.

URL конечной точки:

Примеры

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/page1 и site.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 г. эта функция является экспериментальной. Чтобы воспользоваться им, выполните следующие действия:

  1. Используйте Chrome версии 96 или более поздней (проверить версию можно, введя chrome://version в браузере).
  2. Введите или вставьте chrome://flags/#enable-experimental-web-platform-features в адресную строку Chrome.
  3. Нажмите Включено.
  4. Перезапустите браузер.
  5. Откройте Инструменты разработчика в Chrome.
  6. В Инструментах разработчика Chrome откройте настройки. В разделе "Эксперименты" нажмите Enable Reporting API panel in the Application panel (Включить панель Reporting API на панели "Приложение").
  7. Перезагрузите инструменты разработчика.
  8. Обновите страницу. Отчеты, созданные на странице, на которой открыты инструменты разработчика Chrome, будут перечислены на панели Приложение в разделе Reporting API.
Инструменты разработчика Chrome со списком отчетов.
Инструменты разработчика Chrome показывают отчеты, созданные на вашей странице, и их статус.

Статус отчета

В столбце Статус указано, был ли отчет успешно отправлен.

Статус Описание
Success Браузер отправил отчет, а конечная точка ответила кодом успешного выполнения (200 или другим кодом успешного ответа 2xx).
Pending Браузер пытается отправить отчет.
Queued Отчет создан, и браузер не пытается его отправить. Отчет может иметь статус Queued в двух случаях:
  • Отчет новый, и браузер ждет, не появятся ли другие отчеты, прежде чем попытаться отправить его.
  • Отчет не новый. Браузер уже пытался отправить его, но не смог и теперь ожидает, чтобы повторить попытку.
MarkedForRemoval После нескольких попыток (Queued) браузер прекратил попытки отправить отчет и скоро удалит его из списка отчетов для отправки.

Отчеты удаляются через некоторое время независимо от того, были они отправлены или нет.

Устранение неполадок

Отчеты не создаются или не отправляются на вашу конечную точку? Вот несколько советов по устранению неполадок.

Отчеты не генерируются

Отчеты, которые появляются в инструментах разработчика, были созданы правильно. Если нужного отчета нет в списке:

  • Проверьте, есть ли в ваших правилах report-to. Если он настроен неправильно, отчет не будет создан. Чтобы исправить это, перейдите в раздел Изменение политики. Ещё один способ устранить неполадки – проверить консоль DevTools в 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 и указанные в поле report-to элемента Content-Security-Policy, Cross-Origin-Embedder-Policy и Cross-Origin-Opener-Policy, будут получать отчеты о нарушениях этих правил.

Конечные точки, настроенные в Reporting-Endpoints, также можно указать в поле report-to элемента Content-Security-Policy-Report-Only, Cross-Origin-Embedder-Policy-Report-Only и Cross-Origin-Opener-Policy-Report-Only. Они также будут получать отчеты о нарушениях этих правил.

В обоих случаях отправляются отчеты, но заголовки -Report-Only не применяют правила: ничего не будет заблокировано, но вы получите отчеты о том, что было бы заблокировано.

ReportingObserver

JavaScript API ReportingObserver позволяет отслеживать клиентские предупреждения.

Заголовки ReportingObserver и Reporting-Endpoints создают одинаковые отчеты, но используются в разных случаях.

Используйте ReportingObserver, если:

  • Вы хотите отслеживать только прекращение поддержки или вмешательство браузера. ReportingObserver показывает предупреждения на стороне клиента, например об устаревших функциях и вмешательстве браузера, но в отличие от Reporting-Endpoints не собирает другие типы отчетов, такие как нарушения CSP или COOP/COEP.
  • Реагировать на такие нарушения нужно в реальном времени. ReportingObserver позволяет прикрепить обратный вызов к событию нарушения.
  • Вы хотите добавить в отчет дополнительную информацию, чтобы упростить отладку, используя специальный обратный вызов.

Ещё одно отличие заключается в том, что ReportingObserver настраивается только на стороне клиента. Вы можете использовать его, даже если у вас нет доступа к заголовкам на стороне сервера и вы не можете настроить Reporting-Endpoints.

Дополнительные сведения

Мы благодарим Иэна Клелланда, Эйдзи Китамуру и Милицу Михайлию за их отзывы и предложения по этому документу.