Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як працюють nonce і хеші в CSP, що таке strict-dynamic і як додати nonce до тегів Vite у Laravel?

Перелік дозволених доменів у script-src (script-src 'self' https://cdn.example.com) легко обходиться: на дозволеному CDN знайдеться бібліотека, яку можна використати для виконання довільного коду, або JSONP-ендпойнт. Тому сучасна рекомендація - строга CSP на основі nonce чи хешів.

Nonce - випадкове значення, нове для кожної відповіді. Скрипт виконується, лише якщо має той самий nonce, що й заголовок:

Content-Security-Policy: script-src 'nonce-R4nd0mV4lue' 'strict-dynamic'; object-src 'none'; base-uri 'none'
<script nonce="R4nd0mV4lue" src="/build/app.js"></script>
<script nonce="R4nd0mV4lue">window.App = {...}</script>

Скрипт, вставлений через XSS, nonce не знає - і не виконається.

Хеш - для незмінних інлайнових скриптів: script-src 'sha256-...' з хешем вмісту скрипта. Зручно для статичних сторінок, де nonce генерувати нікому.

'strict-dynamic' - довіра поширюється на скрипти, які завантажив уже дозволений (з nonce) скрипт. Потрібно для сучасних збірок: застосунок динамічно підвантажує частини (import()), а знати їхні адреси заздалегідь неможливо. Браузери з підтримкою strict-dynamic ігнорують перелік доменів і 'self' у script-src.

Laravel і Vite. У middleware - згенерувати nonce, передати Vite і поставити заголовок:

public function handle(Request $request, Closure $next): Response
{
    $nonce = Vite::useCspNonce();   // генерує випадковий nonce, якщо не передано свій

    return $next($request)->withHeaders([
        'Content-Security-Policy' => "script-src 'nonce-{$nonce}' 'strict-dynamic'; object-src 'none'; base-uri 'none'",
    ]);
}

Після цього @vite додає nonce до всіх згенерованих тегів <script> і <link>. Для власних інлайнових скриптів - nonce="{{ Vite::cspNonce() }}".

Пастки:

  • nonce має бути новим на кожну відповідь. Сторінка з nonce, закешована на CDN, віддає всім той самий nonce - захист зникає;
  • обробники в атрибутах (onclick="...") nonce не підтримують - їх переносять у скрипти;
  • Livewire і Alpine обчислюють вирази директив через new Function(), що потребує 'unsafe-eval'. Без нього - CSP-збірка Alpine (у Livewire 4 - опція csp_safe), яка обмежує складні вирази в директивах.

Докладніше в документації: Laravel: CSP nonce для Vite

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання