Используйте API отчетов для отслеживания нарушений безопасности, устаревших вызовов API и многого другого.
Некоторые ошибки случаются только в производстве. Вы не увидите их локально или во время разработки, потому что реальные пользователи , реальные сети и реальные устройства меняют игру. API отчетов помогает выявить некоторые из этих ошибок, например нарушения безопасности или устаревшие вызовы API, которые скоро будут прекращены, на вашем сайте, и передает их в указанную вами конечную точку.
Он позволяет вам объявлять, что вы хотите отслеживать, через HTTP-заголовки и управляется браузером .
Настройка API отчетов дает вам уверенность в том, что, когда пользователи сталкиваются с ошибками такого типа, вы узнаете об этом и сможете их исправить.
В этом посте рассказывается, что может делать этот API и как его использовать. Давайте погрузимся!
Демо и код
Ознакомьтесь с API отчетов в действии, начиная с Chrome 96 и более поздних версий (Chrome Beta или Canary, по состоянию на октябрь 2021 г.).
Обзор
Предположим, что ваш сайт site.example
имеет политику безопасности контента и политику документа. Не знаете, что они делают? Ничего страшного, вы все равно сможете понять этот пример.
Вы решаете следить за своим сайтом, чтобы знать, когда эти политики нарушаются, а также потому, что вы хотите следить за устаревшими или скоро устаревающими 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"
}
Варианты использования и типы отчетов
API отчетов можно настроить так, чтобы он помогал вам отслеживать множество типов интересных предупреждений или проблем, возникающих на вашем сайте:
Тип отчета | Пример ситуации, когда будет создан отчет |
---|---|
Нарушение CSP (только уровень 3) | Вы установили Content-Security-Policy (CSP) на одной из своих страниц, но страница пытается загрузить сценарий, не разрешенный вашим CSP. |
нарушение КоОП | Вы установили на странице Cross-Origin-Opener-Policy , но окно Cross-Origin-Opener пытается напрямую взаимодействовать с документом. |
Нарушение 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-violation или coep . |
url | Адрес документа или работника, из которого был сформирован отчет. Из этого URL-адреса удаляются конфиденциальные данные, такие как имя пользователя, пароль и фрагмент. |
user_agent | Заголовок User-Agent запроса, на основе которого был создан отчет. |
Сертифицированные отчеты
Конечные точки отчетов, имеющие тот же источник , что и страница, создающая отчет, получают учетные данные (файлы cookie) в запросах, содержащих отчеты.
Полномочия могут дать полезный дополнительный контекст отчета; например, постоянно ли учетная запись данного пользователя вызывает ошибки или определенная последовательность действий, предпринятых на других страницах, вызывает отчет на этой странице.
Когда и как браузер отправляет отчеты?
Отчеты доставляются с вашего сайта вне канала : время их отправки на настроенные конечные точки контролируется браузером. Также невозможно контролировать, когда браузер отправляет отчеты; он захватывает, ставит в очередь и автоматически отправляет их в подходящее время.
Это означает, что при использовании API отчетов практически не возникает проблем с производительностью.
Отчеты отправляются с задержкой — до минуты — чтобы увеличить вероятность отправки отчетов пакетами. Это экономит полосу пропускания и учитывает сетевое соединение пользователя, что особенно важно на мобильных устройствах. Браузер также может задержать доставку, если он занят выполнением работы с более высоким приоритетом или если пользователь в это время находится в медленной и/или перегруженной сети.
Сторонние и собственные проблемы
Отчеты, созданные из-за нарушений или устаревания, происходящих на вашей странице, будут отправлены на конечные точки, которые вы настроили. Сюда входят нарушения, допущенные сторонними скриптами, запущенными на вашей странице.
О нарушениях или устареваниях, произошедших в iframe с перекрестным происхождением, встроенном в вашу страницу, не будет сообщено вашим конечным точкам (по крайней мере, по умолчанию). iframe может настроить собственную отчетность и даже отправлять отчеты в службу отчетов вашего сайта, то есть в собственную службу отчетов; но это зависит от сайта в рамке. Также обратите внимание, что большинство отчетов создаются только в том случае, если политика страницы нарушена, и что политики вашей страницы и политики iframe различаются.
Пример с устареваниями
Поддержка браузера
В таблице ниже приведены сведения о поддержке браузером Reporting API v1 , то есть с заголовком Reporting-Endpoints
. Поддержка браузером Reporting API v0 (заголовок Report-To
) такая же, за исключением одного типа отчета: ведение журнала сетевых ошибок не поддерживается в новом Reporting API. Подробности читайте в руководстве по миграции .
Тип отчета | Хром | Хром iOS | Сафари | Firefox | Край |
---|---|---|---|---|---|
Нарушение CSP (только уровень 3)* | ✔ Да | ✔ Да | ✔ Да | ✘ Нет | ✔ Да |
Регистрация сетевых ошибок | ✘ Нет | ✘ Нет | ✘ Нет | ✘ Нет | ✘ Нет |
Нарушение COOP/COEP | ✔ Да | ✘ Нет | ✔ Да | ✘ Нет | ✔ Да |
Все остальные типы: нарушение политики документа, прекращение поддержки, вмешательство, сбой. | ✔ Да | ✘ Нет | ✘ Нет | ✘ Нет | ✔ Да |
В этой таблице представлена только поддержка report-to
с новым заголовком Reporting-Endpoints
. Прочтите советы по миграции отчетов CSP, если вы хотите перейти на Reporting-Endpoints
.
Использование API отчетов
Решите, куда отправлять отчеты
У вас есть два варианта:
- Отправляйте отчеты в существующую службу сбора отчетов.
- Отправляйте отчеты в сборщик отчетов, который вы создаете и управляете самостоятельно.
Вариант 1. Используйте существующую службу сбора отчетов.
Некоторые примеры служб сбора отчетов:
Если вам известны другие решения, сообщите нам об этом, и мы обновим этот пост!
Помимо цен, при выборе сборщика отчетов учитывайте следующие моменты: 🧐
- Поддерживает ли этот сборщик все типы отчетов? Например, не все решения для конечных точек отчетности поддерживают отчеты COOP/COEP.
- Удобно ли вам делиться URL-адресами вашего приложения со сторонним сборщиком отчетов? Даже если браузер удалит конфиденциальную информацию из этих URL-адресов, конфиденциальная информация может попасть в утечку таким образом . Если это звучит слишком рискованно для вашего приложения, используйте собственную конечную точку отчетности.
Вариант 2. Создайте и используйте собственный сборщик отчетов.
Создание собственного сервера, получающего отчеты, не так уж и тривиально. Для начала вы можете создать форк нашего облегченного шаблона. Он создан на основе Express и может получать и отображать отчеты.
Перейдите к сборщику шаблонных отчетов .
Нажмите Remix to Edit , чтобы сделать проект доступным для редактирования.
Теперь у вас есть свой клон! Вы можете настроить его для своих целей.
Если вы не используете шаблон и создаете собственный сервер с нуля:
- Проверьте наличие запросов
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"
Если вы переходите с устаревшего API Reporting API на новый API Reporting, возможно, имеет смысл установить как 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
, могут отправлять отчеты на разные конечные точки.
Чтобы получать отчеты о нарушениях или нарушениях на любой странице вашего сайта, установите заголовок в качестве промежуточного программного обеспечения для всех ответов.
Вот пример в Экспрессе:
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
Пример кода
Чтобы увидеть все это в контексте, ниже приведен пример Node-сервера, который использует Express и объединяет все части, обсуждаемые в этой статье. Он показывает, как настроить отчеты для нескольких различных типов отчетов, и отображает результаты.
Отладка настройки отчетов
Намеренно создавать отчеты
При настройке Reporting API вам, скорее всего, придется намеренно нарушить ваши политики, чтобы проверить, генерируются и отправляются ли отчеты должным образом. Чтобы увидеть пример кода, который нарушает политики и делает другие плохие вещи, которые будут генерировать отчеты всех типов, посмотрите демо-версию .
Экономьте время
Отчеты могут отправляться с задержкой — около минуты, что при отладке является большим сроком. 😴 К счастью, при отладке в Chrome вы можете использовать флаг --short-reporting-delay
чтобы получать отчеты сразу после их создания.
Запустите эту команду в своем терминале, чтобы включить этот флаг:
YOUR_PATH/TO/EXECUTABLE/Chrome --short-reporting-delay
Используйте инструменты разработчика
В Chrome используйте DevTools для просмотра отчетов, которые были отправлены или будут отправлены.
По состоянию на октябрь 2021 года эта функция является экспериментальной. Чтобы использовать его, выполните следующие действия:
- Используйте Chrome версии 96 и новее (проверьте, набрав
chrome://version
в браузере). - Введите или вставьте
chrome://flags/#enable-experimental-web-platform-features
в строку URL-адреса Chrome. - Нажмите Включено .
- Перезапустите браузер.
- Откройте Инструменты разработчика Chrome.
- В Chrome DevTools откройте «Настройки». В разделе «Эксперименты» нажмите «Включить панель Reporting API» на панели «Приложение» .
- Перезагрузите DevTools.
- Перезагрузите страницу. Отчеты, созданные на странице, на которой открыты DevTools, будут перечислены на панели приложений Chrome DevTools в разделе Reporting API .
Статус отчета
Столбец «Статус» сообщает, был ли отчет успешно отправлен.
Статус | Описание |
---|---|
Success | Браузер отправил отчет, и конечная точка ответила кодом успеха ( 200 или другим кодом ответа об успехе 2xx ). |
Pending | В настоящее время браузер пытается отправить отчет. |
Queued | Отчет создан, и браузер в настоящее время не пытается его отправить. Отчет отображается как Queued в одном из этих двух случаев:
|
MarkedForRemoval | После повторной попытки в течение некоторого времени ( Queued ) браузер прекратил попытки отправить отчет и вскоре удалит его из списка отчетов для отправки. |
Отчеты удаляются через некоторое время независимо от того, успешно ли они отправлены.
Поиск неисправностей
Отчеты не создаются или не отправляются на вашу конечную точку должным образом? Вот несколько советов по устранению этой неполадки.
Отчеты не формируются
Отчеты, отображаемые в DevTools, были созданы правильно. Если ожидаемый отчет не отображается в этом списке:
- Проверьте
report-to
в вашей политике. Если это неправильно настроено, отчет не будет создан. Чтобы исправить это, перейдите в раздел «Изменить политику» . Дополнительный способ устранения этой неполадки — проверить консоль DevTools в Chrome: если в консоли появляется ошибка, связанная с ожидаемым вами нарушением, это означает, что ваша политика, вероятно, настроена правильно. - Имейте в виду, что в этом списке отображаются только отчеты, созданные для документа, в котором открыты DevTools. Один пример: если ваш сайт
site1.example
встраивает iframesite2.example
, который нарушает политику и, следовательно, создает отчет, этот отчет будет отображаться в DevTools, только если вы откроете iframe в его собственном окне и откроете DevTools для этого окна.
Отчеты создаются, но не отправляются или не получаются
Что делать, если вы видите отчет в DevTools, но ваша конечная точка его не получает?
- Обязательно используйте короткие задержки . Возможно, причина, по которой вы не видите отчет, заключается в том, что он еще не отправлен!
Проверьте конфигурацию заголовка
Reporting-Endpoints
. Если с ним возникнут проблемы, правильно сформированный отчет не будет отправлен. В DevTools статус отчета в этом случае останетсяQueued
(он может перейти наPending
, а затем быстро вернуться вQueued
при попытке доставки). Некоторые распространенные ошибки, которые могут привести к этому:Конечная точка используется, но не настроена. Пример:
Document-Policy: document-write=?0;report-to=endpoint-1; Reporting-Endpoints: default="https://reports.example/default"
Конечная точка
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
API JavaScript ReportingObserver
может помочь вам наблюдать за предупреждениями на стороне клиента.
ReportingObserver
и заголовок Reporting-Endpoints
создают отчеты, которые выглядят одинаково, но допускают несколько разные варианты использования.
Используйте ReportingObserver
, если:
- Вы хотите только отслеживать устаревание и/или вмешательство браузера.
ReportingObserver
отображает предупреждения на стороне клиента , такие как устаревание и вмешательство браузера, но в отличие отReporting-Endpoints
он не фиксирует никакие другие типы отчетов, такие как нарушения CSP или COOP/COEP. - Вам необходимо реагировать на эти нарушения в режиме реального времени.
ReportingObserver
позволяет прикрепить обратный вызов к событию нарушения. - Вы хотите прикрепить к отчету дополнительную информацию для облегчения отладки с помощью пользовательского обратного вызова .
Еще одно отличие состоит в том, что ReportingObserver
настраивается только на стороне клиента: вы можете использовать его, даже если у вас нет контроля над заголовками на стороне сервера и вы не можете устанавливать Reporting-Endpoints
.
Дальнейшее чтение
- Руководство по переходу с Reporting API v0 на v1
- ОтчетностьНаблюдатель
- Спецификация: устаревший API отчетов (v0).
- Спецификация: новый API отчетов (v1).
Изображение героя от Nine Koepfer / @enka80 на Unsplash , отредактировано. Большое спасибо Яну Клелланду, Эйджи Китамуре и Милице Михайлии за их обзоры и предложения по этой статье.