Метаданные Fetch
Метаданные Fetch
Метаданные Fetch — это термин для группы HTTP-заголовков запроса, которые сообщают серверу о контексте, в котором выполняется запрос.
Помимо прочего, метаданные Fetch позволяют серверу узнать:
-
Представляет ли запрос переход между документами, запрос субресурса или был явно выполнен из JavaScript, например с помощью API
fetch(). -
Связь между запрашивающей ресурс стороной и запрашиваемым ресурсом: относятся ли они к одному источнику, к одному сайту или к совершенно разным сайтам.
Используя сведения из этих заголовков, чтобы разрешать или запрещать определённые запросы, сервер может защититься от междоменных атак, таких как подделка межсайтовых запросов (CSRF) и различные межсайтовые утечки.
Заголовки метаданных Fetch
Спецификация метаданных Fetch определяет четыре заголовка метаданных Fetch:
Как и все заголовки с префиксом Sec-, они относятся к запрещённым заголовкам запроса, то есть их нельзя задавать или изменять в клиентском коде сайта.
Sec-Fetch-Dest
Этот заголовок указывает назначение запроса. Этот атрибут определён в Fetch API, где доступен как свойство Request.destination.
Грубо говоря, можно считать, что он указывает, как будет использоваться полученный ресурс.
Для большинства замещаемых элементов значение заголовка обозначает элемент, для которого будет использоваться этот ресурс, например iframe, object, audio или video. Значение image указывает, что ресурс будет использоваться как изображение, на которое ссылается замещаемый элемент, например HTML-элемент <img>, CSS-свойство background-image, элемент SVG <image> или любой другой элемент веб-платформы, использующий изображения, загруженные как субресурсы.
К другим интересным значениям назначения относятся:
document-
Запрос предназначен для нового документа, являющегося целью перехода верхнего уровня (например, когда пользователь нажимает ссылку на странице или отправляет форму).
script-
Ресурс будет использоваться как скрипт, загруженный HTML-элементом
<script>или вызовомimportScripts()в веб-воркере.Для обозначения других мест, где ресурс используется как скрипт, применяются более конкретные значения, например для рабочих областей (
audioworkletиpaintworklet) и воркеров (sharedworker,serviceworkerиworker). empty-
Для запроса не определено назначение: помимо прочих возможных причин, это значение используется, если запрос является результатом вызова
fetch().
Полный список возможных значений приведён на справочной странице этого заголовка.
Sec-Fetch-Mode
Этот заголовок указывает режим запроса. Как и назначение, режим определён в Fetch API, где доступен как свойство Request.mode.
Чаще всего используются следующие значения:
-
Запрос представляет собой переход между документами (например, пользователь нажимает ссылку).
no-cors-
Запрос выполнен в режиме
no-cors.Это означает, что запрос разрешён для другого источника без отправки сервером соответствующих заголовков CORS, однако JavaScript, выполняющийся на клиенте, не может получить доступ к ответу (он является непрозрачным).
Это режим по умолчанию для страниц, загружающих субресурсы, такие как изображения, шрифты, скрипты и таблицы стилей. Этим объясняется, почему другому сайту по умолчанию разрешено использовать субресурсы вашего сайта, даже если вы не настроили CORS для такого доступа.
cors-
Если запрос выполняется к другому источнику, сервер должен ответить соответствующими заголовками CORS, иначе запрос завершится ошибкой. Если сервер ответит нужными заголовками CORS, вызывающей стороне будут доступны тело ответа и некоторые заголовки.
Чаще всего этот режим используется для междоменных запросов из JavaScript с помощью Fetch API, когда запрашивающей стороне нужен доступ к полученному ресурсу (например, при вызове fetch для получения JSON с сервера).
same-origin-
Запрос разрешён, только если запрашивающая сторона и запрашиваемый ресурс относятся к одному источнику.
Sec-Fetch-Site
Этот заголовок указывает связь между источником запрашиваемого ресурса и источником стороны, запрашивающей ресурс.
Он указывает, поступает ли запрос:
- С того же источника, что и запрашиваемый ресурс.
- С другого источника, но с того же сайта.
- С другого сайта.
Например, если пользователь нажимает ссылку на странице по адресу https://books.example.org/authors, браузер отправляет запрос на получение документа, указанного в качестве цели ссылки. В таблице ниже показаны значения соответствующего заголовка Sec-Fetch-Site для разных адресов ссылок:
| Цель ссылки |
значение Sec-Fetch-Site |
|---|---|
https://books.example.org/titles | same-origin |
https://login.example.org/ | same-site |
https://books.example.com/titles | cross-site |
Аналогичные соответствия действуют для других HTTP-запросов, например:
- Отправка форм через атрибут
actionэлемента<form>. - Запросы субресурсов, таких как изображения, шрифты или скрипты.
- Запросы, выполненные с помощью API
fetch().
Заголовок Sec-Fetch-Site также может иметь значение none для запросов, у которых нет сайта-источника, включая, например, запросы, отправленные при вводе URL в адресную строку браузера или нажатии закладки. В спецификации они называются запросами, инициированными непосредственно пользователем.
Sec-Fetch-User
Этот заголовок включается только в том случае, если запрос инициирован действием пользователя (например, нажатием ссылки); если он включён, его значение всегда равно ?1.
Междоменные атаки
Метаданные Fetch особенно полезны для защиты от междоменных атак. Обычно такие атаки направлены на пользователя, у которого есть учётная запись на легитимном сайте и который вошёл на этот сайт. Злоумышленник создаёт сайт, отправляющий междоменный запрос к легитимному сайту, а затем обманом заставляет пользователя выполнить этот запрос.
Примечание: В этом руководстве мы используем термин междоменная атака, хотя многие атаки обычно называют межсайтовыми.
Источник — более строгое понятие, чем сайт. В частности, сайт включает поддомены домена, а источник — нет: поэтому https://example.org и https://login.example.org относятся к одному сайту, но к разным источникам.
Это означает, что все межсайтовые атаки являются междоменными, но некоторые междоменные атаки не являются межсайтовыми. Например, если злоумышленник получает контроль над поддоменом сайта, он может атаковать сайт с помощью междоменных запросов к тому же сайту. Чтобы охватить и такие атаки, мы используем более строгое понятие.
Например, на сайте злоумышленника может быть элемент <form>, отправляющий данные на легитимный сайт. Для некоторых междоменных атак взаимодействие с пользователем вообще не требуется: страница злоумышленника может просто выполнить запрос fetch() к легитимному сайту при загрузке, и тогда для выполнения междоменного запроса пользователю достаточно открыть страницу злоумышленника.
Поскольку запрос отправлен из браузера пользователя, он будет содержать все файлы cookie, установленные легитимным сайтом для этого пользователя, в том числе cookie, которые сайт использует для его идентификации. Поэтому запрос будет выполнен с привилегиями этого пользователя.
Можно выделить два типа междоменных атак:
-
Атаки межсайтовой подделки запроса (CSRF): при таких атаках междоменный запрос выполняет на легитимном сервере какое-либо важное действие, используя параметры, заданные злоумышленником. Например, запрос просит сервер перевести деньги со счёта пользователя-жертвы на счёт злоумышленника.
-
Межсайтовые утечки: при таких атаках злоумышленник использует запрос, чтобы получить сведения о связи пользователя с целевым сайтом, часто через побочные каналы, например события ошибок.
Большинство сайтов хотят запрещать одни междоменные запросы и разрешать другие: например, если запрещать все междоменные запросы, никто не сможет перейти на ваш сайт с другого сайта!
С помощью метаданных Fetch сервер может создать политику разрешения или запрета междоменных запросов на основе подробных сведений об их контексте.
Политика изоляции ресурсов
Один из распространённых типов политики называется политикой изоляции ресурсов. Получив запрос, сервер анализирует заголовки метаданных Fetch и разрешает только:
- Запросы с того же источника (а иногда и запросы с того же сайта, если вы доверяете своим поддоменам).
- Запросы навигации верхнего уровня с другого источника, чтобы пользователи могли перейти на ваш сайт по ссылкам с других сайтов.
- Запросы к определённым конечным точкам, предназначенным для междоменного доступа, в том числе использующим CORS.
Например, следующий код Express разрешает только запросы с того же источника, запросы, инициированные непосредственно пользователем, и запросы навигации.
function isAllowed(req) {
// Allow same-origin requests
// Allow directly user-initiated requests (from bookmarks, address bar etc.)
const secFetchSite = req.headers["sec-fetch-site"];
if (secFetchSite === "same-origin" || secFetchSite === "none") {
return true;
}
// Allow cross-site navigations, such as clicking links
const secFetchMode = req.headers["sec-fetch-mode"];
if (secFetchMode === "navigate" && req.method === "GET") {
return true;
}
// Deny everything else
return false;
}
app.get("/admin", (req, res) => {
res.setHeader("Vary", "sec-fetch-site, sec-fetch-mode");
if (isAllowed(req)) {
// Respond with the admin page if the user is admin
getAdminPage(req, res);
} else {
res.status(403).send("Forbidden");
}
});
Обратите внимание, что код также отправляет заголовок ответа Vary. Благодаря этому, если ответ будет помещён в кеш, он будет возвращаться только на запросы с такими же значениями используемых нами заголовков метаданных Fetch.
На странице «Политика изоляции ресурсов» приведены дополнительные примеры кода для такой политики.
См. также
- CSRF
- Межсайтовые утечки
- Защитите свои ресурсы от веб-атак с помощью метаданных Fetch (web.dev)
- Метаданные Fetch (вики XS-Leaks)
© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Fetch_metadata