2026 удалённый Mac: ловушки фронтенда —
CSP, nonce, strict-dynamic и таблица ошибок Safari
Для кого: команды с CSP, nonce или hash, где ломается только Safari. Дальше — WebKit vs Chromium, таблица nonce/hash, strict-dynamic, проверка на удалённом Mac, таблица ошибок консоли, пример заголовка и три шага приёмки. См. также деплой и Safari и CQ и @layer.
01 CSP: основы и отличия Safari (WebKit)
Без 'unsafe-inline' в script-src каждый инлайн нужен с nonce в заголовке и на теге или с SHA-256 hash. WebKit иначе формулирует отказы и строже к обработчикам, javascript: и воркерам — QA только в Chrome пропускает реальные сбои Safari.
На удалённом Mac держите одинаковый CSP на стейдже и в проде, фиксируйте версию WebKit. Для style-src заранее решите nonce, hash или исключения для виджетов со стилями.
- Динамическая подгрузка: GTM и поздние бандлы должны наследовать доверие nonce либо покрываться hash на стабильных фрагментах.
- iframe: жёсткий
frame-srcрежет оплату и OAuth без явного сообщения в UI. - Кэш HTML: устаревшая страница со старым nonce даёт хаотичные отказы — ключи кэша должны учитывать ротацию nonce.
02 Таблица: nonce и hash в конфигурации CSP
Nonce — для SSR и HTML на запрос; hash — для редко меняющихся инлайнов. Оба сочетаются с поэтапным ужесточением и reporting.
| Тема | Nonce | SHA-256 hash |
|---|---|---|
| Шаблон в заголовке | script-src 'nonce-<random>' …; то же значение в <script nonce="…">. |
script-src 'sha256-<base64>'; байты инлайна должны совпадать побайтно. |
| Лучше всего для | SSR, edge-шаблоны, цепочки strict-dynamic. | Фиксированные boot-сниппеты, небольшой JSON-LD под контролем репозитория. |
| Операционный риск | Забытый сброс кэша HTML или middleware без ротации nonce. | Сборка и минификация меняют пробелы — hash пересчитывать при каждом изменении. |
| Заметка для Safari | Проверьте, что hydration и все chunk-loader’ы получают nonce из серверной оболочки. | После любого форматирования инлайна пересчитайте hash и обновите заголовок. |
На каждый запрос генерируйте случайный nonce в res.locals.cspNonce и выставляйте заголовок:
const n = res.locals.cspNonce;
res.setHeader('Content-Security-Policy', [
`default-src 'self'`,
`script-src 'nonce-${n}' 'strict-dynamic' https:`,
`style-src 'self' 'nonce-${n}'`,
`object-src 'none'`,
`base-uri 'none'`,
`frame-ancestors 'none'`
].join('; '));
Когда цепочка nonce полностью покрывает загрузку скриптов, список https: можно сузить. Отладку в Safari см. в FAQ по Web Inspector на Mac и iOS.
03 Внедрение strict-dynamic: пошагово
'strict-dynamic': скрипты с nonce или hash тянут потомков без расширения allowlist в script-src; динамика часто не доверяет «голым» URL — первый синхронный скрипт должен нести nonce.
- Корневой загрузчик: первый синхронный
<script>с nonce инициирует весь граф зависимостей. - Ленивые чанки: подгружаются только из кода, уже помеченного как доверенный; «голые» теги третьих сторон без nonce не подходят.
- Сокращение хостов: после стабилизации цепочки уберите лишние источники из
script-src, но честно расширьтеconnect-srcпод API. - Сначала Report-Only: воспроизведите продакшен-nonce в
Content-Security-Policy-Report-Only, соберите отчёты, затем включайте enforce. - Воркеры: service worker и отдельные worker-скрипты должны укладываться в ваши правила статики или nonce; проверьте регистрацию в Safari.
04 Удалённая проверка Safari и WebKit
Арендованный Mac — нативный Safari пользователей: HTTPS-стейджинг, «Разработка», Web Inspector; плюс смоук Playwright webkit на том же хосте.
Один узел для Node и Safari ускоряет отделение CSP от регрессий CSS/JS.
- Приватное окно снижает влияние расширений, подменяющих заголовки или скрипты.
- Консоль и сеть: ищите пометки вроде
blocked:cspна отклонённых ресурсах. - Playwright webkit на том же хосте — быстрый смоук; OAuth и оплату всё равно проверьте вручную в Safari.
| Сигнал в консоли Safari | Вероятная директива | Направление исправления |
|---|---|---|
| Refused to execute… нет hash, nonce или unsafe-inline | script-src |
Синхронизируйте nonce в заголовке и тегах; сбросьте кэш HTML при ротации. |
| Refused to load… violates Content Security Policy | connect-src / frame-src |
Добавьте хосты API; разрешите нужные origin iframe для SaaS. |
| Applying inline style violates CSP | style-src |
Вынесите в файл, hash или тот же nonce через общий слой шаблона. |
05 FAQ: типичные блокировки и интерпретация
Краткие ответы перед релизом; смысл совпадает с разметкой FAQPage в JSON-LD.
- Chrome ок, Safari нет? WebKit строже по ряду шаблонов; финальная подпись только в реальном Safari.
- strict-dynamic и список хостов? Динамические загрузки опираются на цепочку nonce, а не на «голые» URL в allowlist.
- Один nonce на всех? Категорически нет: уникальный непредсказуемый nonce на каждый HTML-ответ.
- Инлайн-стили и виджеты? Планируйте hash, nonce или вынесение в CSS; иначе Safari стабильно рубит оформление платёжных форм.
06 Три шага приёмки перед релизом
Приёмка: CSP стейджа как в проде; чистая консоль на ключевых маршрутах; версии ОС/Safari и артефакты в тикете. HTML с nonce — без долгого кэша без nonce-aware ключей; корневой скрипт strict-dynamic под вашим контролем.
- Шаг 1 — паритет политики: байт-в-байт тот же CSP, что в проде, включая reporting, если он включён.
- Шаг 2 — консоль без висящих ошибок: логин, оплата, дашборды, страницы ошибок и пустые состояния.
- Шаг 3 — доказательства: строки версий Safari/WebKit, скриншоты или HAR в тикете релиза.
Арендуйте удалённый Mac для приёмки CSP в Safari
Прод-CSP на Mac Mini, нарушения WebKit, три шага приёмки. Тарифы и помощь без обязательного входа.