OSEN-НИЙ SAAALEСкидка 50% на виртуальный хостинг и VDS
до 30.11.2025 Подробнее
Выберите продукт

SRI для статики: защищаем CDN‑ассеты через integrity и кэшируем без риска

Subresource Integrity (SRI) позволяет безопасно подключать скрипты и стили с CDN: браузер сверяет хеш содержимого и блокирует несовпадения. Покажу, как корректно генерировать хеши, добавить crossorigin и CORS, а также включить долгий TTL и immutable без риска сломать загрузку.
SRI для статики: защищаем CDN‑ассеты через integrity и кэшируем без риска

Зачем нужен SRI и в чём идея

Когда вы подключаете скрипты и стили с CDN или другого домена, вы доверяете внешнему источнику. Subresource Integrity (SRI) решает эту проблему просто: вы сообщаете браузеру хеш ожидаемого содержимого, а он сверяет фактические байты и, если не совпадает — не исполняет и не применяет ресурс. Так можно смело давать статике «вечный» TTL, зная, что даже при компрометации CDN браузер не примет подмену.

На практике SRI — это атрибут integrity с баз64‑хешем по алгоритму sha256, sha384 или sha512. Рекомендуется sha384 как золотая середина по стойкости/размеру. Для кросс‑доменных ассетов нужен ещё атрибут crossorigin и корректные CORS‑заголовки на стороне источника.

Базовое подключение: script и stylesheet

Добавляем SRI к скриптам и стилям. Для кросс‑доменных подключений указываем crossorigin="anonymous", чтобы браузер выполнял CORS‑запрос и смог проверить целостность.

<!-- JS с CDN -->
<script src="https://cdn.example.com/js/app.min.js" integrity="sha384-BASE64HASH" crossorigin="anonymous"></script>

<!-- CSS с CDN -->
<link rel="stylesheet" href="https://cdn.example.com/css/app.min.css" integrity="sha384-BASE64HASH" crossorigin="anonymous">

Важно: для ресурсов с другого домена сервер должен отдать Access-Control-Allow-Origin (обычно * или ваш домен). Без CORS браузер получит «непрозрачный» ответ и SRI не сработает.

Дополнительно: rel="preload" и rel="modulepreload" тоже поддерживают integrity — указывайте хеш, как и для stylesheet/script.

Генерация SRI‑хешей через OpenSSL и Node.js

Как генерировать хеши SRI

Хеш нужно считать по исходным байтам файла без сжатия. Браузер проверяет SRI уже после декомпрессии, так что хеш должен соответствовать оригинальному содержимому, а не .gz/.br вариантам.

Через OpenSSL

# sha384 в Base64
openssl dgst -sha384 -binary dist/app.min.js | openssl base64 -A
# Вставьте результат как integrity="sha384-РЕЗУЛЬТАТ"

Через Node.js (одной строкой)

node -e "fs=require('fs');c=fs.readFileSync('dist/app.min.js');console.log('sha384-'+require('crypto').createHash('sha384').update(c).digest('base64'))"

Через Python

python3 -c "import base64,hashlib,sys;d=open('dist/app.min.css','rb').read();print('sha384-'+base64.b64encode(hashlib.sha384(d).digest()).decode())"

Подпишите все публичные ассеты: основные бандлы JS/CSS, иногда и критически важные веб‑шрифты. Помните, что ресурсы, на которые ссылается CSS (шрифты, картинки), SRI не покрывает автоматически — они загружаются отдельно. Для них используйте версионирование файла и длинный TTL.

Кэширование «на века» без риска

SRI сам по себе ничего не кэширует, но даёт уверенность включить жёсткое кэширование: Cache-Control: public, max-age=31536000, immutable. Если байты изменятся — хеш станет другим, вы обновите атрибут integrity и одновременно путь/имя файла (или версию в пути), тем самым инвалидация кэша произойдёт автоматически.

Рекомендованный паттерн

  • Контент‑хеш в имени файла: app.3f1a2b7.css, vendor.a9c0e1d.js.
  • Сервер/ориджин отдает длинный TTL и immutable.
  • HTML ссылается на конкретную версию и содержит SRI‑хеш именно этой версии.

Так вы получаете идеальную комбинацию: быстрая доставка из кэша и гарантия неизменности через SRI. Подробно о стратегиях версионирования и кэшировании через CDN/S3 — в материале о версионировании ассетов и TTL.

Настройки сервера/ориджина: заголовки и CORS

Чтобы SRI на кросс‑доменных ресурсах стабильно работал, включите CORS и правильное кэширование. Пример для Nginx (папка /assets/):

location /assets/ {
    add_header Cache-Control "public, max-age=31536000, immutable" always;
    add_header Access-Control-Allow-Origin "*" always;
    add_header Access-Control-Allow-Methods "GET, HEAD, OPTIONS" always;
    add_header Timing-Allow-Origin "*" always;
    etag on;
    expires max;
}

Пояснения:

  • Access-Control-Allow-Origin позволяет браузеру выполнить CORS‑запрос и проверить SRI.
  • immutable сообщает, что ресурс не меняется в течение max-age.
  • etag on и expires max не противоречат; ETag полезен для редких revalidate в некоторых цепочках, хотя при «контент‑хеш в имени» он почти не нужен.

Если используете CDN поверх ориджина, убедитесь, что CDN не меняет содержимое «на лету» (автоминификация, переупорядочивание CSS, инъекция JS). Любая модификация сломает проверку SRI. Отключите подобные оптимизации для путей с ассетами. Если нужен подробный разбор CORS‑заголовков, загляните в нашу шпаргалку по заголовкам CORS для Nginx и Apache.

Полный контроль заголовков на уровне веб‑сервера удобнее на собственном VDS; там проще настроить кеширование, CORS и мидлвары, не завися от «магии» CDN.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Автоматизация: обновляем SRI при каждом билде

Ручное обновление integrity ошибок не прощает. Проще включить генерацию хешей в пайплайн сборки. Вариант «на коленке» для статической выдачи: скрипт, который пробегает по HTML и подставляет актуальные хеши.

Пример простого обновления в Bash

# Генерация SRI для всех .js и .css, вывод в TSV: файл\thash
find dist -type f \( -name "*.js" -o -name "*.css" \) -print0 | while IFS= read -r -d '' f; do h=$(openssl dgst -sha384 -binary "$f" | openssl base64 -A); echo -e "${f}\tsha384-${h}"; done

# Далее используйте любой скрипт/шаблонизатор, чтобы подставить значение в атрибут integrity в HTML.

В экосистемах бандлеров есть готовые плагины для генерации SRI‑хешей и их встройки в HTML‑темплейты (Webpack, Rollup, Vite). Критерии выбора: поддержка sha384, корректная работа с crossorigin, совместимость с HTML‑плагином.

Алгоритмы и совместимость

  • Используйте sha384. Он поддерживается всеми современными браузерами и даёт хороший запас прочности.
  • Можно указывать несколько алгоритмов через пробел, но практической пользы сейчас немного.
  • Старые браузеры без поддержки SRI (редкость) просто проигнорируют атрибут и загрузят ресурс. Если важен «жёсткий отказ» — не подключайте критичный код оттуда для таких браузеров или сервируйте бандл с того же домена.

Типичные ошибки и как их избежать

  1. Хеш считан по сжатому файлу. Всегда хешируйте оригинал (до gzip/brotli). Иначе браузер после декомпрессии получит другие байты.
  2. Нет CORS‑заголовков. Для SRI на кросс‑домене браузеру нужен CORS. Добавьте Access-Control-Allow-Origin.
  3. CDN мутирует контент. Отключите автоминификацию/«ускорители», которые меняют байты.
  4. Забыли обновить integrity. Включите генерацию в CI/CD, не правьте хеши вручную.
  5. Версионирование только query‑параметром. Некоторые прокси/кэши игнорируют их. Надёжнее — контент‑хеш в имени файла или в пути.
  6. Inline‑скрипты и стили. SRI на inline не работает. Для них используйте CSP с nonce или хешами, если требуется контроль целостности.

Проверка и отладка

Проверьте работу так:

  • Откройте DevTools → Network. Убедитесь, что статические файлы грузятся с кэша (200 from disk cache/304) и содержат Cache-Control: max-age=31536000, immutable.
  • Проверьте, что ответы от CDN/ориджина включают Access-Control-Allow-Origin для путей ассетов.
  • Нарочно измените один байт файла на сервере и не меняйте integrity: браузер должен заблокировать загрузку и показать ошибку «Failed to find a valid digest in the 'integrity' attribute».

Конфигурация Nginx для CORS и долгого кэширования ассетов

CSS, шрифты и другие подводные камни

SRI покрывает только сам подключаемый ресурс. Если вы ставите SRI на CSS, это не защищает @font-face и картинки внутри; их нужно версионировать и кэшировать отдельно. Для веб‑шрифтов важно наличие Access-Control-Allow-Origin, иначе браузер может заблокировать кросс‑доменную загрузку, особенно при использовании crossorigin.

Также учитывайте, что preload и modulepreload в современных браузерах поддерживают integrity аналогично link rel="stylesheet", но проверяйте конкретные таргеты: поведение могло отличаться в старых версиях движков.

SRI и CSP: как дополняют друг друга

SRI защищает от подмены байтов ресурса. Content Security Policy (CSP) ограничивает источники, с которых вообще можно грузить скрипты и стили. Комбинируйте: жёсткий script-src/style-src с указанием ваших доменов и SRI на внешних ассетах. И, разумеется, раздавайте всё по HTTPS — оформить валидные SSL-сертификаты нужно в первую очередь.

Процесс обновлений

Устройте пайплайн так, чтобы «обновление ассета» означало: новый файл с контент‑хешем в имени, новый integrity в HTML, релиз. Старые версии остаются в CDN до их естественного вымывания из кэшей, но никому не вредят. При смене CDN‑провайдера ссылки могут поменяться, но SRI останется прежним — важно, чтобы байты совпадали.

Итоги

Subresource Integrity — простой и мощный механизм: один атрибут integrity плюс корректный crossorigin и CORS‑заголовки. Он позволяет без страха включать жёсткое кэширование ассетов на год и дольше, ускоряя загрузку и не рискуя безопасностью. Автоматизируйте генерацию хешей в сборке, добавьте версионирование файлов и отключите на CDN любые модификации контента — и проблема «сломался сторонний скрипт» перестанет вас беспокоить.

Поделиться статьей

Вам будет интересно

Nginx proxy_cache_path: разбор keys_zone, max_size, inactive и тонкая настройка OpenAI Статья написана AI (GPT 5)

Nginx proxy_cache_path: разбор keys_zone, max_size, inactive и тонкая настройка

Если вы кэшируете ответы через Nginx, директива proxy_cache_path определяет каталог на диске, глубину levels, объём keys_zone и пр ...
Apache mod_md и ACME: автоматизация SSL без и с cron OpenAI Статья написана AI (GPT 5)

Apache mod_md и ACME: автоматизация SSL без и с cron

Покажу, как включить модуль mod_md в Apache и настроить автоматизацию ACME с Let’s Encrypt без внешних скриптов. Разберём рабочие ...
HAProxy HTTP Cache: практическое руководство для реверс‑прокси OpenAI Статья написана AI (GPT 5)

HAProxy HTTP Cache: практическое руководство для реверс‑прокси

Разбираем встроенный HTTP cache в HAProxy: когда он уместен, как писать правила и учитывать headers, выбирать TTL, нормализовать з ...