Откат междоменной изоляции: чек-лист изменения заголовков
Определите, какие URL остаются изолированными, кто отвечает за каждый класс ресурсов и как поэтапный выпуск возвращает прежние заголовки.
BotBrowser Team
Нужна структурированная документация по теме Платформа?
Эта статья относится к редакционной библиотеке. Для пошаговой настройки, справки и постоянных обновлений переходите сразу в соответствующий раздел docs.
Изменить междоменную изоляцию значит изменить политику ответа работающего продукта, и сложно здесь не включение. Этот чек-лист начинается там, где заканчивается исправление ошибки not cross-origin isolated: когда первая страница уже доказала изолированное состояние, нужно решить, какие URL должны остаться такими, кто отвечает за каждый встроенный ресурс и что делает поэтапный выпуск, если сценарий ломается.
BotBrowser может загрузить объявленную сборку браузера в собственный контекст и записать, равно ли window.crossOriginIsolated true для этого ответа; он не может отправить COOP или COEP за какой-то хост, изменить ответ CORS или CORP поставщика и не может восстановить сценарий, который новая политика разделяет.
Кратко
- Перечислите URL, которым нужна изоляция, и остальные оставьте неизолированными намеренно.
- Сопоставьте каждый класс встроенных ресурсов с владельцем политики до изменения заголовка.
- Выпускайте по доле трафика или по хосту, а не открывайте все маршруты сразу.
- Согласуйте условие отката и прежний набор заголовков до первого производственного запроса.
Содержание
- Определите URL, которым нужна изоляция
- Сопоставьте классы ресурсов с владельцами
- Выпускайте поэтапно
- Определите откат
- Поставляйте резерв и доказательства
- Практический итог
Определите URL, которым нужна изоляция
Изоляция принадлежит документам, а не сайту. Продукту она обычно нужна на одной поверхности, например на странице, запускающей Worker с разделяемой памятью, и не нужна на странице обзора, в потоке входа или в колбэке OAuth. Отправка Cross-Origin-Opener-Policy: same-origin и Cross-Origin-Embedder-Policy: require-corp повсюду расширяет радиус поражения и ничего не даёт страницам, которые никогда не пользуются функцией, доступной только в изолированном состоянии. Перед расширением области перечитайте руководство по границам CORS, где уже описаны междоменные зависимости. Прежде чем расширять область, сверьтесь с материалом о границах CORS: часть ресурсов там уже описана как междоменная зависимость.
Записывайте область как список шаблонов URL, например /app/editor/* и /auth/*, а не как домен. Включите пути документов, которые обязаны быть изолированы, пути, которые должны остаться неизолированными, и пути колбэков, поведение окна которых вы изменить не можете. Цепочка перенаправлений, заканчивающаяся изолированным документом, остаётся изолированной; заканчивающаяся неизолированным, нет, и эта разница теряется, когда область записана как «всё приложение».
Фиксируйте область рядом с записью выпуска (docs/cross-origin-isolation-scope.md), с датой и владельцем. Когда позже появляется новый маршрут, область подсказывает инженеру, наследует ли он изоляцию родительского шаблона или ему нужна собственная политика. Это и есть разница между осознанной политикой и политикой, расползшейся случайно.
Сверяйте область с картой сайта и реестром маршрутов, а не по памяти, и запускайте такую сверку по расписанию, если набор маршрутов часто меняется. Маршрут, сгенерированный шаблоном, может отдать документ, который правило заголовков не покрывает, особенно если у шаблона своя разметка и другой канонический хост. Первое место, где изоляция удивляет команду, это страница, которую никто не перечислил.
Держите область проверяемой
Проверка области это ещё и момент убедиться, что неизолированные страницы действительно не нуждаются в функции, доступной только при изоляции. Поищите в приложении SharedArrayBuffer, crossOriginIsolated и Atomics прежде чем объявить страницу вне области. Страница, которая проверяет булево значение и уходит на резерв, может оставаться неизолированной; страница, создающая разделяемый буфер без проверки, упадёт при первом же вызове функции.
Если странице изоляция нужна только под флагом функции, записывайте флаг вместе с шаблоном. Включение флага на хосте, который политику не отправляет, даёт сбой выполнения, похожий на дефект кода, и запись флага позволяет рецензенту увидеть, что политика никогда не действовала, а не что функция сломалась.
Записывайте область как проверяемый список
Область, живущая в презентации, проверить нельзя, поэтому ожидаемое состояние держите строкой в scopes.tsv или полем JSON, которое читает сборка. Храните её как список шаблонов с ожидаемым состоянием для каждого, чтобы последующее изменение можно было сравнить с ним, а не обсуждать. Полезная запись называет шаблон, ожидаемое состояние изоляции, причину и владельца, который этого потребовал.
Ожидаемое состояние не всегда «изолировано». Многим продуктам нужно, чтобы документ оставался неизолированным, потому что встроенный виджет чата, фрейм оплаты или старый отчёт зависят от ресурсов, которые никто не может изменить в том же окне. Запись этого намерения не даёт последующей уборке «починить» намеренно исключённую страницу и сломать сценарий.
Группируйте шаблоны по пути ответа, а не только по префиксу URL. После переписывания два пути под одним префиксом могут обслуживаться разными источниками, и правило CDN, действующее для одного, может не действовать для другого. Когда список перерастает несколько записей, добавьте проверку, что каждый версионированный маршрут либо соответствует шаблону, либо явно исключён.
Держите список рядом с конфигурацией развёртывания и обновляйте его в том же изменении, что добавляет или убирает маршрут. Область, исправленная задним числом, уже была неверной в продакшене, и вызванный ею сбой выглядит как случайная несогласованность, а не пропущенная запись.
Сравнивайте «до» и «после» на одной сборке
Измерение, делающее выпуск проверяемым, это сравнение, а не один замер; сохраняйте scope-before.json и scope-after.json. Снимите базовую линию на предпроизводственном хосте до изменения и повторите те же проверки после, на той же сборке браузера и с теми же fixture. Один замер после изменения не скажет, откуда неожиданное значение: из политики или оно было там и раньше.
Записывайте три поля на страницу: переданные значения заголовков, булево значение изоляции в рантайме и первый отказавший ресурс, если он есть. Заголовки говорят, что отправил сервер, булево значение что принял браузер, отказавший ресурс какой класс требует внимания, когда первые два не совпадают.
Отбирайте хотя бы один URL на шаблон вместо одного общего. Цепочка перенаправлений, локализованный хост и вариант с завершающей косой чертой могут дать разные итоговые ответы, и шаблон силён ровно настолько, насколько проверен его самый непроверенный член.
Повторяйте измерение после изменения CDN, обновления сервис-воркера или переезда хостинга, даже если код приложения не двигался. Эти три события меняют отдаваемый ответ, не затрагивая репозиторий, и именно поэтому запись политики до них может вводить в заблуждение.
Сопоставьте классы ресурсов с владельцами
Изоляция меняет то, что может загружаться, поэтому каждому классу встроенных ресурсов нужны решение и владелец. Группируйте по способу отдачи, а не по команде-заказчику: ответ политики зависит от ответа сервера, а не от запроса.
Фреймы самый чувствительный класс. Междоменный iframe нуждается в ответе, совместимом с COEP, или заголовке CORP, и фрейм поставщика без них откажет, как только встраивающий документ включит COEP. Вход через всплывающее окно относится к тому же классу: COOP разделяет связь с opener, и поставщик, ожидающий window.opener, это заметит. Записывайте поставщика, источник фрейма и то, что его документация говорит о совместимости с изоляцией.
Скрипты, таблицы стилей, шрифты и изображения образуют следующий класс. Их обычно отдаёт CDN, и ответ это заголовок CORS или Cross-Origin-Resource-Policy: cross-origin. Правило CDN, работающее для поддомена, может не применяться к каноническому хосту, поэтому называйте того, кто может изменить ответ именно для того хоста, который вызывается.
Медиа это отдельный класс и обычно самый медленный в изменениях. Конечные точки видео и аудио могут быть подписанными, перенаправляющими или зависящими от региона, и каждый случай меняет видимые заголовки. Проверяйте на подписанном URL, похожем на производственный, а не на статичной выборке.
Аналитика и менеджеры тегов это класс, который вероятнее всего откажет молча. Многие из них загружают дополнительные скрипты во время работы, так что проверенный URL не тот, который выполняется. Записывайте, что они могут отказывать, и решайте, приемлемо ли это, поскольку маяк аналитики, переставший отчитываться, редко блокирует сценарий пользователя, но меняет данные, на которые вы опираетесь.
Для каждого класса назовите политику, владельца и проверку. Проверка это один запрос на класс, записанный с итоговым URL и значением заголовка, сделавшим его совместимым. Класс без проверки это класс, который вы предполагаете, а не знаете, и предположение превращает поэтапный выпуск в неожиданность.
Выпускайте поэтапно
Выпускайте по трафику, а не по амбициям. Поэтапный выпуск даёт первые производственные доказательства от небольшой группы, пока прежняя политика остаётся на расстоянии одного изменения конфигурации. Выбирайте измерение этапа по тому, что ваша инфраструктура откатывает быстрее: доля на границе, правило заголовков на одном хосте или канареечный маршрут с тем же кодом.
Согласуйте единицу этапа со сценарием пользователя. Доля трафика может отправить одного пользователя в изолированную версию на первой странице и в неизолированную на колбэке, и это даёт сбой, который выглядит случайным и таковым не является. Липкая доля или группировка по хосту держит один сценарий под одной политикой на всё время.
Определите порядок поверхностей. Начинайте с поверхности с наименьшим числом встроенных зависимостей и самым понятным резервом, а заканчивайте той, что несёт вход или оплату. Смысл порядка в том, чтобы узнать классы ресурсов в дешёвом месте до дорогого.
Наблюдайте правильные сигналы в окне выпуска. crossOriginIsolated: false на странице, где должно быть true, это результат конфигурации. Заблокированный ресурс это результат политики против одного класса. Пользователь, который не может войти, это результат приложения, и он важнее обоих, потому что никакое изолированное состояние не стоит сломанного сценария.
Держите окно достаточно коротким для отката и достаточно длинным, чтобы увидеть полный сценарий, и запишите его в запись до начала, чтобы никто не продлил его случайно. Окно, которое заканчивается раньше, чем пользователь войдёт и вернётся через колбэк, не проверило самые вероятные к поломке пути.
Определите откат
Откату нужны условие, действие и проверка, согласованные до начала. Условие это фраза, которую инженер поддержки может применить не спрашивая владельца выпуска: ключевой сценарий падает у доли затронутых пользователей выше указанной, или владелец класса не успевает сделать ресурс совместимым в течение окна.
Действие это прежний набор заголовков плюс прежний путь приложения, оба доступны и проверены. Откат только заголовков, восстанавливающий COOP и COEP при включённой изолированной функции, даёт страницу, которая сообщает false и затем падает в рантайме; путь приложения должен меняться вместе с политикой.
Проверка это та же проверка, что доказала изолированное состояние, только наоборот: хосте этапа возвращается к прежним заголовкам, crossOriginIsolated равен false там, где ожидается, резервный путь завершает сценарий, и классы, которым требовалась новая политика, больше не нужны. Запишите результат с датой и именем того, кто принял решение.
Запишите, чего откат не покрывает. Кэшированный документ, сервис-воркер или правило периферии с долгим TTL могут продолжать отдавать новую политику после смены источника. Отметьте шаг очистки и хосты, которых он касается, потому что неполный откат это политика, которая выглядит откаченной и не является таковой.
Проверяйте запись отката после окончания выпуска, использовался он или нет. Откат, который не понадобился, всё равно говорит, сработало ли действие, и следующее изменение заголовков может переиспользовать процедуру вместо повторного поиска.
Поставляйте резерв и доказательства
Выберите резерв, который продукт реально может выпустить
Каждой функции, доступной только в изоляции, нужен резерв, с которым пользователь завершит задачу (fallback: passed), и резерв должен быть более простым путём, а не второй системой. Worker с разделяемой памятью может уйти на цикл в главном потоке с индикатором прогресса. Функция, которой изоляция нужна для производительности, может деградировать до медленного пути с видимым уведомлением. Функция, которой изоляция нужна для корректности, уйти на резерв не может, и это продуктовое решение, которое надо поднять до выпуска, а не во время.
Проверяйте резерв теми же fixture, что и изолированный путь. Резерв, который никогда не работал на данных, близких к производственным, это непроверенный путь, и окно выпуска не время обнаруживать, что он падает на большом входе.
Определите владельца резерва. Если его поставляет команда приложения, а заголовок включает платформа, резерв принадлежит приложению и должен быть в списке выпуска, а не появляться потом. Запись выпуска должна называть резерв и место его проверки, чтобы поддержка могла направить пользователя туда, не дожидаясь диагностики.
Держите доказательства короткими для действий
Запись выпуска, которую читает только специалист, не будет прочитана во время инцидента. Сведите её к списку области, владельцам классов, измерению этапа, замерам до и после, условию отката и резерву. Каждый пункт помещается в строку и при необходимости ссылается на длинный документ.
Поставьте дату и назовите того, кто принял политику, вместе с локальным часовым поясом планирования окна. Запись без владельца становится записью, которую никто не защищает, и следующее изменение стартует с более слабой позиции.
Выводите запись из оборота, когда политика стабильна достаточно долго и прежнего набора заголовков нет ни в одной разворачиваемой конфигурации. До тех пор запись это единственное описание того, как достигнуто текущее состояние.
Практический итог
Изоляция это политика ответа с областью, владельцами и планом выпуска. Определите URL, сопоставьте классы ресурсов, выпускайте по трафику и согласуйте условие отката до первого производственного запроса. Используйте этот чек-лист вместе с исправлением изоляции, руководством по границам CORS и обзором защищённых контекстов.
Источники
Эта статья входит в руководство: Поверхности веб-платформы: карта проверки
Похожие статьи
Исправить not cross-origin isolated: COOP, COEP и SharedArrayBuffer
ПлатформаПолитика разрешений для встроенных возможностей браузера
РазвертываниеРазвёртывание и выпуск браузера: операционная карта
ПлатформаOrigin-Agent-Cluster: предсказуемая изоляция памяти JavaScript
ПлатформаГраницы CORS в браузере: заголовки, preflight, учетные данные и кэш
ПлатформаПримечания к версиям браузера для web-команд
Переведите BotBrowser из исследований в продакшн
Используйте эти руководства, чтобы понять модель, а затем перейти к кроссплатформенной валидации, изолированным контекстам и масштабируемому браузерному развертыванию.