Генератор SRI-хеша

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

Публичный адрес https://, до 5 MB. Файл скачивается нашим сервером, хешируется и удаляется.

Или попробуйте https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js, https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css

Или вычислите хеш файла на своём устройстве

Для файла, которого ещё нет в сети, или того, который вы предпочитаете оставить при себе. Хеш вычисляет ваш браузер: то, что вы сюда перетащите или вставите, нам не отправляется.

Выберите файл или перетащите его в любое место этого поля.

Печать на коде, который размещаете не вы

Когда ваша страница загружает библиотеку с CDN, вы даёте чужому серверу право выполнять код перед вашими посетителями. Если этот сервер взломают или проект перейдёт в другие руки, тот же адрес может начать отдавать что-то другое: скиммер банковских карт, криптомайнер или перенаправление. Страница продолжает работать, и вы ничего не замечаете. Такое уже случалось с настоящими библиотеками, которыми пользовались сотни тысяч сайтов.

Subresource Integrity (SRI) это функция браузера, которая решает эту проблему. Вы добавляете в тег отпечаток проверенного вами файла, вычисленный хеш-функцией, например SHA-384. Браузер скачивает файл, заново вычисляет отпечаток и выполняет файл, только если они совпадают. Измените хоть один байт, и отпечаток получится другим, так что файл будет заблокирован.

<script src="https://cdn.example.com/lib@2.4.1/lib.min.js"
        integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
        crossorigin="anonymous"></script>

Что вычисляет и проверяет эта страница

Когда вы указываете адрес, наш сервер один раз скачивает файл и отправляет заголовок Origin, как это делает браузер для тега с crossorigin. Хеш берётся от тела после распаковки gzip или Brotli, то есть ровно от того, что хеширует браузер. Вы получаете полный тег с SHA-384, а также значения SHA-256 и SHA-512.

Правильный хеш ещё не гарантирует, что тег заработает, поэтому мы читаем из ответа ещё четыре вещи:

ПроверкаПочему это важно
Access-Control-Allow-OriginДля файла с другого источника браузеру нужно это разрешение, прежде чем он сможет сравнивать байты. Без него тег с integrity не срабатывает никогда. Нет заголовка: ошибка.
Версия в адресе/3.7.1/ или @5.3.3 всегда отдают один и тот же файл. @latest, @5, название ветки, версия только в ?ver= или отсутствие версии означают, что файл может измениться, и тогда страница сломается. Предупреждение.
Cache-ControlСрок жизни в год или immutable говорит о замороженном файле. Срок меньше суток говорит о том, что адрес рассчитан на изменения.
Content-TypeСкрипты должны приходить как JavaScript, а таблицы стилей как text/css. Просмотрщики исходных файлов часто отдают text/plain, и браузеры такое отклоняют.

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

Второе поле хеширует перетащенный файл или вставленный код средствами самого браузера, crypto.subtle. Ничего не загружается на сервер.

Как использовать тег и не сломать страницу

  1. Сначала зафиксируйте версию. Замените library@latest на точный протестированный вами выпуск, затем создайте хеш для этого адреса.
  2. Оставьте crossorigin="anonymous". Без него браузер делает запрос, который ему не разрешено проверять, и блокирует файл.
  3. Загрузите страницу и откройте консоль. Несовпадение отображается там как неудачная проверка целостности с названием файла.
  4. Обновляйтесь осознанно. Новой версии библиотеки нужны новый адрес и новый хеш. Это немного работы, но в этом и смысл: ничего не меняется, пока вы этого не скажете.

Для файлов на вашем собственном домене SRI мало что даёт против злоумышленника, который уже управляет вашим сервером: он может поменять и страницу, и хеш. Но это всё равно полезно, когда страницы и ресурсы раздаются с разных систем, например HTML с вашего сервера, а файлы из вашего собственного бакета CDN.

Ограничения: один запрос из одного места. Сервер может отдавать другие байты другому браузеру или региону, и мы не проверяем, что файл безопасен, только что он тот же самый. Атрибут integrity распространяется на файл, в теге которого стоит, а не на скрипты, которые этот файл загружает потом.

Частые вопросы

Какой хеш выбрать: sha256, sha384 или sha512?

Браузеры принимают все три, и ни один не считается слабым. SHA-384 это общепринятый вариант. Его публикуют CDN и показывает большинство документации, так что используйте его, если политика не требует иного.

Почему скрипт перестаёт загружаться после добавления integrity?

Обычно причин три. Сервер не отправляет Access-Control-Allow-Origin или в теге нет crossorigin="anonymous". Файл изменился с момента вычисления хеша, потому что адрес не привязан к версии. Или что-то между сервером и браузером переписывает файл, например прокси, минифицирующий скрипты. Консоль браузера скажет, что именно.

Можно ли использовать SRI с Google Fonts, Google Analytics или Stripe?

Нет. Эти адреса отдают содержимое, которое владельцы обновляют когда захотят, а таблица стилей шрифтов отличается от браузера к браузеру. Фиксированный хеш заблокирует их при следующем изменении. Ограничьте их через Content-Security-Policy.

Меняется ли хеш, если сервер сжимает файл?

Нет. Браузер проверяет файл после распаковки, так что gzip, Brotli и zstd ничего не меняют. А вот минификация или переформатирование файла его меняют.

Поддерживают ли изображения и шрифты атрибут integrity?

Пока нет. Браузеры применяют его к <script> и к <link> для таблиц стилей, preload и modulepreload. На других элементах он игнорируется.

Как вычислить такой же хеш в командной строке?

С OpenSSL: openssl dgst -sha384 -binary file.js | openssl base64 -A, затем добавьте sha384- перед результатом.