ASP.NET Core Blazor WebAssembly .NET сбои кэширования пакетов и проверки их целостности

Примечание.

Это не последняя версия этой статьи. Текущий выпуск можно найти в версии этой статьи о .NET 10.

Предупреждение

Эта версия ASP.NET Core больше не поддерживается. Для получения дополнительной информации см. Политику поддержки .NET и .NET Core. Текущий выпуск можно найти в версии этой статьи о .NET 10.

В этой статье объясняется кэширование ресурсов для Blazor WebAssembly и методы диагностики и устранения ошибок целостности данных.

Blazor WebAssembly Когда приложение загружается в браузере, приложение загружает ресурсы загрузки с сервера:

  • Код JavaScript для инициализации приложения
  • .NET среды выполнения и сборок
  • Локализованные данные

Конфигурация Blazor загрузки, встроенная в dotnet.js, содержит манифест с характеристиками файлов, составляющих приложение, которое должно быть скачано, вместе с хэшами содержимого каждого файла. Файлы приложения предварительно загружаются и кэшируются браузером.

Примечание.

†In .NET 10 или более поздней версии файл манифеста blazor.boot.json больше не присутствует. При обновлении приложения, использующего файл манифеста для пользовательской обработки, рекомендуется собирать сведения непосредственно из сборки.

Когда Blazor WebAssembly загружает файлы запуска для приложения, он инструктирует браузер совершить проверку целостности этих ответов. Blazorотправляет хэш-значения SHA-256 для DLL (), WebAssembly (.dll.wasm) и других файлов. Хэши файлов кэшированных файлов сравниваются с хэшами в конфигурации загрузки. Браузер генерирует ошибку, если проверка целостности скачанного файла не удалась.

Для получения дополнительных сведений см. следующие разделы статьи Основы: Статические файлы.

За исключением файла манифеста загрузки Blazor (blazor.boot.json), файлы WebAssembly .NET среды выполнения и пакета приложений кэшируются на клиентах. Конфигурация Blazor загрузки содержит манифест файлов, составляющих приложение, которое должно быть загружено вместе с хэшом содержимого файла, которое используется для определения того, изменились ли какие-либо из ресурсов загрузки. Blazor кэширует скачанные файлы с помощью API кэша браузера.

Когда Blazor WebAssembly загружает файлы запуска для приложения, он инструктирует браузер совершить проверку целостности этих ответов. Blazor отправляет хэш-значения SHA-256 для DLL (.dll), WebAssembly (.wasm) и других файлов в Blazor конфигурации загрузки, которая не кэшируется на клиентах. Хэши файлов кэшированных файлов сравниваются с хэшами в Blazor конфигурации загрузки. Для кэшированных файлов с совпадающим хэшем Blazor использует кэшированные файлы. В противном случае файлы запрашиваются с сервера. После скачивания файла его хэш снова проверяется на целостность. Браузер генерирует ошибку, если проверка целостности скачанного файла не удалась.

Алгоритм Blazor для управления целостностью файлов:

  • Гарантирует, что приложение не будет загружать несогласованный набор файлов, например, если новое развертывание применяется к вашему веб-серверу, пока пользователь скачивает файлы приложения. Использование несогласованных файлов может привести к неправильной работе приложения.
  • Гарантирует, что браузер пользователя никогда не будет кэшировать несогласованные или недопустимые ответы, что может помешать запуску приложения, даже если пользователь вручную обновляет страницу.
  • Делает безопасным кэширование ответов и не проверяет изменения на стороне сервера до тех пор, пока не изменятся сами ожидаемые хэши SHA-256, поэтому последующие загрузки страниц включают меньше запросов и выполняются быстрее.

Если веб-сервер возвращает ответы, не соответствующие ожидаемым хэшам SHA-256, в консоли разработчика браузера отобразится примерно такая ошибка:

Не удалось найти допустимый дайджест в атрибуте 'integrity' для ресурса 'https://myapp.example.com/_framework/MyBlazorApp.dll' с вычисленной целостностью SHA-256 'IIa70iwvmEg5WiDV17OpQ5eCztNYqL186J56852RpJY='. Ресурс заблокирован.

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

Справочный источник начальной загрузки Blazor WebAssembly см. в файле Boot.WebAssembly.ts в репозитории dotnet/aspnetcore GitHub.

Примечание.

Ссылки на справочную документацию .NET обычно ведут на ветвь репозитория по умолчанию, которая представляет собой текущую разработку следующего релиза .NET. Чтобы выбрать тег для определенного выпуска, используйте раскрывающийся список ветвей switch или тегов . Дополнительные сведения см. в разделе Как выбрать тег версии исходного кода ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Диагностика проблем целостности

При создании приложения сформированный манифест загрузки описывает хэши SHA-256 ресурсов загрузки на момент создания выходных данных сборки. Проверка целостности проходит до тех пор, пока хэши SHA-256 в манифесте загрузки соответствуют файлам, доставленным в браузер.

Распространенные причины сбоя:

  • Ответ веб-сервера — это ошибка (например, ошибка 404 — не найдена или 500 — внутренняя ошибка сервера) вместо файла, запрошенного браузером. Сообщается браузером как ошибка проверки целостности, а не как ошибка ответа.
  • Содержимое файлов по какой-либо причине изменилось в период между их сборкой и доставкой в браузер. Это может произойти:
    • Если вы или средства сборки вручную изменили выходные данные сборки.
    • Если какие-то аспекты процесса развертывания изменили файлы. Например, если вы используете механизм развертывания на основе Git, имейте в виду, что Git прозрачно преобразует окончания строк в стиле Windows в окончания строк в стиле Unix, если вы коммитите файлы на Windows и извлекаете их в Linux. Изменение концов строк в файле приводит к изменению хэша SHA-256. Чтобы избежать этой проблемы, рассмотрите возможность использовать .gitattributes для обработки артефактов сборки в качестве binary файлов.
    • Веб-сервер изменяет содержимое файла в процессе их предоставления. Например, некоторые сети распространения содержимого (CDN) автоматически пытаются минифицировать HTML, тем самым изменяя его. Возможно, вам придется отключить эти функции.
  • Манифест загрузки не загружается должным образом или неправильно кэшируется на клиенте. Распространенные причины включают одно из следующих причин:
    • Неправильно настроенный или неисправный пользовательский код разработчика.
    • Один или несколько неправильно настроенных промежуточных уровней кэширования.

Чтобы выяснить, что из перечисленного применимо в вашем случае, сделайте следующее.

  1. Узнайте, какой файл вызывает ошибку, прочитав сообщение об ошибке.
  2. Откройте средства разработчика браузера и перейдите на вкладку "Сеть ". При необходимости перезагрузите страницу, чтобы просмотреть список запросов и ответов. Найдите в этом списке файл, который вызвал ошибку.
  3. Проверьте код состояния в ответе HTTP. Если сервер возвращает что-либо, отличное от 200, — ОК (или другой код состояния 2xx), у вас есть проблема на стороне сервера для диагностики. Например, код состояния 403 означает проблему с авторизацией, а код состояния 500 — неопределенную ошибку в работе сервера. Просмотрите журналы на стороне сервера, чтобы диагностировать и исправить приложение.
  4. Если код состояния равен 200 — ОК для ресурса, просмотрите содержимое ответа в средствах разработчика браузера и убедитесь, что содержимое соответствует ожидаемым данным. Например, довольно часто ошибка в настройке маршрутизации приводит к тому, что запросы возвращают ваши index.html данные даже для других файлов. Убедитесь, что ответы на запросы .wasm являются двоичными файлами WebAssembly и что ответы на запросы .dll являются двоичными файлами сборки .NET. Если нет, у вас проблема маршрутизации на стороне сервера, которую нужно диагностировать.
  1. Узнайте, какой файл вызывает ошибку, прочитав сообщение об ошибке.
  2. Откройте средства разработчика браузера и перейдите на вкладку "Сеть ". При необходимости перезагрузите страницу, чтобы просмотреть список запросов и ответов. Найдите в этом списке файл, который вызвал ошибку.
  3. Проверьте код состояния в ответе HTTP. Если сервер возвращает что-либо, отличное от 200, — ОК (или другой код состояния 2xx), у вас есть проблема на стороне сервера для диагностики. Например, код состояния 403 означает проблему с авторизацией, а код состояния 500 — неопределенную ошибку в работе сервера. Просмотрите журналы на стороне сервера, чтобы диагностировать и исправить приложение.
  4. Если код состояния равен 200 — ОК для ресурса, просмотрите содержимое ответа в средствах разработчика браузера и убедитесь, что содержимое соответствует ожидаемым данным. Например, довольно часто ошибка в настройке маршрутизации приводит к тому, что запросы возвращают ваши index.html данные даже для других файлов. Убедитесь, что ответы на запросы .wasm являются двоичными файлами WebAssembly и что ответы на запросы .dll являются двоичными файлами сборки .NET. Если нет, у вас проблема маршрутизации на стороне сервера, которую нужно диагностировать.
  5. Для проверки целостности опубликованных и развернутых результатов приложения используйте скрипт PowerShell для устранения неполадок.

Если вы убедились, что сервер возвращает данные в предположительно правильном формате, значит что-то еще изменяет содержимое файлов в период между сборкой и доставкой. Для анализа этой ситуации сделайте следующее:

  • Изучите цепочку инструментов сборки и механизм развертывания на случай, если файлы изменяются после сборки. Выше описан пример таких изменений, связанный с преобразованием концов строк в файлах при работе с Git.
  • Изучите конфигурацию веб-сервера или CDN на предмет возможного динамического изменения ответов (например, попытка минимизировать HTML). При этом сжатие HTTP (например, в формате content-encoding: br или content-encoding: gzip) на стороне веб-сервера считается допустимым, так как не влияет на результат после распаковки. Однако это не хорошо, если веб-сервер изменяет несжатые данные.

Скрипт PowerShell для устранения проблем целостности

Используйте в PowerShell скрипт integrity.ps1 для проверки опубликованного и развернутого приложения Blazor. Скрипт предоставляется для PowerShell Core 7 или более поздней версии в качестве начальной точки, если в приложении есть проблемы с целостностью, которые платформа Blazor не может распознать. Для приложений может потребоваться настройка скрипта, в том числе при запуске в PowerShell более поздней версии, чем версия 7.2.0.

Скрипт проверяет файлы, расположенные в папке publish и скачанные из развернутого приложения, чтобы обнаружить проблемы в разных манифестах, содержащих хэши целостности. При этих проверках должны быть обнаружены наиболее распространенные проблемы:

  • Вы изменили файл в опубликованных выходных данных, не зная этого.
  • Приложение было неправильно развернуто в целевом объекте развертывания или что-то изменилось в среде целевого объекта развертывания.
  • Существует разница между развернутым приложением и результатами публикации приложения.

Вызовите скрипт в командной оболочке PowerShell с помощью следующей команды:

.\integrity.ps1 {BASE URL} {PUBLISH OUTPUT FOLDER}

В следующем примере сценарий выполняется в локально запущенном приложении в https://localhost:5001/:

.\integrity.ps1 https://localhost:5001/ C:\TestApps\BlazorSample\bin\Release\net6.0\publish\

Заполнители:

  • {BASE URL}: URL-адрес развернутого приложения. Требуется завершающая косая черта (/).
  • {PUBLISH OUTPUT FOLDER}: Путь к папке или расположению приложения publish , в котором приложение публикуется для развертывания.

Примечание.

При клонирование репозитория dotnet/AspNetCore.Docs GitHub скрипт integrity.ps1 может быть помещен в карантин с помощью Bitdefender или другого сканера вирусов, присутствующих в системе. Как правило, файл находится в ловушке эвристической технологией сканирования вирусов, которая просто ищет шаблоны в файлах, которые могут указывать на наличие вредоносных программ. Чтобы предотвратить помещение файла в карантин сканером вирусов, добавьте исключение в сканер вирусов перед клонированием репозитория. В следующем примере показан типичный путь к скрипту в системе Windows. При необходимости измените путь для других систем. Плейсхолдер {USER} — это сегмент пути пользователя.

C:\Users\{USER}\Documents\GitHub\AspNetCore.Docs\aspnetcore\blazor\host-and-deploy\webassembly\_samples\integrity.ps1

Предупреждение. Создание исключений сканера вирусов опасно и должно выполняться только в том случае, если вы уверены, что файл является безопасным.

Сравнение контрольной суммы файла с его корректным значением не гарантирует безопасность файла, но изменение файла таким образом, чтобы сохранить соответствие контрольной сумме, является непростой задачей для злоумышленников. Поэтому контрольные суммы полезны в качестве общего подхода к обеспечению безопасности. Сравните контрольную сумму локального файла integrity.ps1 с одним из приведенных ниже значений.

  • SHA256: 32c24cb667d79a701135cb72f6bae490d81703323f61b8af2c7e5e5dc0f0c2bb
  • MD5: 9cee7d7ec86ee809a329b5406fbf21a8

Получите контрольную сумму файла в операционной системе Windows с помощью следующей команды. Укажите путь и имя файла для заполнителя {PATH AND FILE NAME}, а также тип контрольной суммы, которую нужно создать для заполнителя {SHA512|MD5}, SHA256 или MD5:

CertUtil -hashfile {PATH AND FILE NAME} {SHA256|MD5}

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

Дополнительные сведения см. в разделе Microsoft Defender для бизнеса.

Отключение проверки целостности для приложений, не относящихся к PWA

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

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

Чтобы отключить проверки целостности, вручную загрузите ресурсы загрузки на стороне клиента и избегайте передачи integrity параметра вызову fetch .

Чтобы отключить проверки целостности, добавьте следующий фрагмент в группу свойств в файле проекта Blazor WebAssembly приложения .csproj:

<BlazorCacheBootResources>false</BlazorCacheBootResources>

BlazorCacheBootResources также отключает Blazorповедение кэширования по умолчанию для .dll, .wasm и других файлов на основе хэшей SHA-256, так как это свойство запрещает доверять правильности хэшей SHA-256. Даже с этой настройкой стандартный кэш HTTP браузера может кэшировать эти файлы, но произойдет это или нет, зависит от конфигурации вашего веб-сервера и заголовков cache-control, которые он предоставляет.

Примечание.

Свойство BlazorCacheBootResources не отключает проверки целостности для прогрессивных веб-приложений (PWA). Руководство, касающееся ППВА, см. в разделе "Отключение проверки целостности для ППВА".

Мы не можем предоставить исчерпывающий список сценариев, в которых требуется отключение проверки целостности. Серверы могут отвечать на запрос произвольным образом, что выходит за рамки платформы Blazor. Платформа позволяет предыдущему подходу сделать приложение запущенным за счет потери гарантии целостности, которую может предоставить приложение. Опять же, мы не рекомендуем отключать проверку целостности, особенно для производственных развертываний. Разработчики должны стремиться решить основную проблему с целостностью, которая приводит к сбою проверки целостности.

Несколько общих сценариев, которые могут вызвать проблемы с целостностью:

  • Выполнение через HTTP, когда нельзя проверить целостность.
  • Если ваш процесс развертывания каким-либо образом изменяет файлы после публикации.
  • Если ваш хост каким-либо образом изменяет файлы.

Отключение проверки целостности для PWA

Шаблон Blazor для прогрессивного веб-приложения (PWA) содержит рекомендуемый файл service-worker.published.js, который отвечает за получение и хранение файлов приложений для автономного использования. Этот процесс отличается от обычного механизма запуска приложения и использует собственную логику проверки целостности.

В файле service-worker.published.js есть следующая строка:

.map(asset => new Request(asset.url, { integrity: asset.hash }));

Чтобы отключить проверку целостности, удалите параметр integrity из этой строки, заменив ее следующим текстом:

.map(asset => new Request(asset.url));

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