Как сгенерировать SRI-хеш
- Выбран режим SRI. В блоке Хеши: отметьте sha256, sha384 и/или sha512; по умолчанию отмечен sha384.
- Установите Источник на Файл и перетащите файлы
.jsили.css. Тип тега определяется по расширению файла. - Или переключите Источник на Текст, вставьте содержимое файла в поле Содержимое файла (вставьте), выберите Тег (
<script>или<link rel="stylesheet">) и введите Путь или URL, по которому файл будет доступен. - Скопируйте значение
integrityили весь HTML-тег. Несколько отмеченных алгоритмов выводятся в одном атрибуте через пробел.
Перетаскивать файл надёжнее, чем вставлять. Текстовое поле браузера превращает окончания строк CRLF в LF, а отсутствующий или лишний перевод строки в конце меняет хеш; инструмент напоминает об обоих случаях.
Что такое значение integrity
Значение SRI состоит из названия алгоритма, дефиса и хеша точных байтов файла в Base64. Для файла app.js с одной строкой console.log('hello'); и переводом строки после неё:
<script src="https://cdn.example.com/app.js"
integrity="sha384-eEqgsNuDqSzbarn2kIY7c4WH6zkoJrjJRQIhlYgVwRR+6Eb8tkfTItTNLlIjbE3O"
crossorigin="anonymous"></script>
Без завершающего перевода строки та же строка даёт хеш sha384-v393mDht/MNBowq0Z9UpetDvKE6u6EdCihklP1GZs66vL1YCFm1Z4Q4wJtb94rY9. Браузер скачивает файл, хеширует полученное тело (уже после снятия сжатия gzip или Brotli при передаче, так что сжатие роли не играет) и отказывается выполнять или применять файл, если ни один из указанных хешей не совпал.
Когда SRI имеет смысл
SRI защищает, когда ваш код раздаёт кто-то другой: публичный CDN, хостинг стороннего виджета, бакет, общий с другими командами. Если такой сервер взломают и подменят файл, браузеры заблокируют изменённый файл и не выполнят его на ваших страницах.
SRI подходит для файлов, которые никогда не меняются по своему URL, например library@1.2.3/dist/lib.min.js. Не подходит он для:
- URL вроде
/latest/или@1, которые переезжают на новые релизы. - Ответов, которые различаются в зависимости от браузера или региона, например CSS некоторых веб-шрифтов, где правила
@font-faceзависят от user agent. - Скриптов, которые поставщик намеренно обновляет на месте, как многие загрузчики аналитики и чатов. Здесь придётся выбирать между SRI и обновлениями от поставщика.
Для ваших собственных файлов на вашем домене SRI даёт мало: злоумышленник, который может изменить файл, обычно может изменить и HTML. Здесь лучше подходит Content Security Policy; эту сторону закрывают генератор CSP nonce и CSP-хеши из SHA-256 в Base64.
CORS и атрибут crossorigin
Файл с другого источника с атрибутом integrity должен загружаться в режиме CORS, а сервер должен разрешать это заголовком Access-Control-Allow-Origin (у публичных CDN обычно *). Именно это запрашивает crossorigin="anonymous"; сгенерированный тег всегда его содержит. Без CORS браузер не может прочитать байты, чтобы их захешировать, и блокирует файл, а в консоли появляется сообщение об ошибке integrity или CORS.
Файлам с того же источника этот атрибут не нужен, но и не вредит.
SRI-хеши при сборке
Если файлов больше нескольких, считайте хеши на этапе сборки:
openssl dgst -sha384 -binary app.js | openssl base64 -A
const crypto = require("crypto");
const fs = require("fs");
const integrity = "sha384-" +
crypto.createHash("sha384").update(fs.readFileSync("app.js")).digest("base64");
console.log(integrity);
Для файла из примера обе команды выводят значение eEqgsNuD…, приведённое выше. У сборщиков часто есть плагин, который сам вписывает атрибут в HTML, поэтому хеши не отстают от сборок. Чтобы проверить полученное значение, перетащите файл сюда и сравните; сравнение точное, символ в символ.
Вопросы и ответы
Какой алгоритм выбрать для SRI?
Обычно SHA-384: его же чаще всего публикуют CDN. Браузеры принимают sha256, sha384 и sha512; если указано несколько, они берут самый стойкий из имеющихся и игнорируют более слабые.
Почему браузер блокирует мой скрипт после добавления integrity?
Либо байты отличаются от тех, что вы хешировали, либо файл приходит с другого источника без CORS. Посмотрите сообщение в консоли, сравните с файлом, который сервер отдаёт на самом деле, и убедитесь, что в ответе есть Access-Control-Allow-Origin, а у тега есть crossorigin="anonymous".
Можно ли использовать SRI с файлом, который меняется, например по ссылке «latest»?
Нет. Хеш фиксирует одну конкретную версию, поэтому любое обновление ломает страницу, пока вы не обновите хеш. Ссылайтесь на URL с версией или на время выкатки указывайте старый и новый хеш рядом.
Как сгенерировать SRI-хеш в командной строке?
Выполните openssl dgst -sha384 -binary app.js | openssl base64 -A и допишите перед результатом sha384-. Флаг -binary обязателен: без него вы закодируете hex-текст.