Перейти к содержанию

Сборка CSP⚓︎

Livewire предлагает CSP-безопасную сборку, которая позволяет использовать приложения Livewire в средах со строгими заголовками политики безопасности контента (CSP), запрещающими 'unsafe-eval'.

Что такое политика безопасности контента (CSP)?⚓︎

Политика безопасности контента (CSP) — это стандарт безопасности, помогающий предотвратить различные типы атак, включая межсайтовый скриптинг (XSS) и атаки с внедрением кода. CSP работает, позволяя веб-разработчикам контролировать, какие ресурсы браузеру разрешено загружать и выполнять.

Одной из самых строгих директив CSP является 'unsafe-eval'. Если она опущена, это предотвращает выполнение JavaScript-кода динамически через такие функции, как eval(), new Function() и аналогичные конструкции, которые компилируют и выполняют строки как код во время выполнения.

Почему CSP влияет на Livewire⚓︎

По умолчанию Livewire (и лежащий в его основе фреймворк Alpine.js) использует объявления new Function() для компиляции и выполнения JavaScript-выражений из атрибутов HTML, таких как:

<button wire:click="$set('count', count + 1)">Увеличить</button>
<div wire:show="user.role === 'admin'">Админка</div>

Хотя этот подход намного быстрее и безопаснее, чем прямое использование eval(), он всё же нарушает директиву CSP 'unsafe-eval', которую применяют многие приложения, заботящиеся о безопасности.

Включение CSP-безопасного режима⚓︎

Чтобы включить CSP-безопасный режим Livewire, вам необходимо изменить конфигурацию вашего приложения:

Конфигурация⚓︎

В файле config/livewire.php установите параметр csp_safe в значение true:

'csp_safe' => true,

Влияние на Alpine.js⚓︎

Важно: когда вы включаете CSP-безопасный режим в Livewire, это также влияет на всю функциональность Alpine.js в вашем приложении. Alpine автоматически начнет использовать свой CSP-безопасный вычислитель, что означает, что все выражения Alpine в вашем приложении будут подчиняться тем же ограничениям синтаксического анализа.

Именно здесь большинство разработчиков заметят ограничения, так как выражения Alpine, как правило, сложнее типичных выражений Livewire.

Что поддерживается⚓︎

Сборка CSP поддерживает большинство распространённых выражений JavaScript, которые вы используете в Livewire:

Базовые выражения Livewire⚓︎

<!-- Это работает -->
<button wire:click="increment">+</button>
<button wire:click="decrement">-</button>
<button wire:click="reset">Сброс</button>
<button wire:click="save">Сохранить</button>
<input wire:model="name">
<input wire:model.live="search">

Вызовы методов с параметрами⚓︎

<!-- Это работает -->
<button wire:click="updateUser('John', 25)">Обновить данные пользователя</button>
<button wire:click="setCount(42)">Установить счётчик</button>
<button wire:click="saveData({ name: 'John', age: 30 })">Сохранить объект</button>

Доступ к свойствам и их обновление⚓︎

<!-- Это работает -->
<input wire:model="user.name">
<input wire:model="settings.theme">
<button wire:click="$set('user.active', true)">Активировать</button>
<div wire:show="user.role === 'admin'">Админка</div>

Базовые выражения в Alpine⚓︎

<!-- Это работает -->
<div x-data="{ count: 0, name: 'Livewire' }" wire:ignore>
    <button x-on:click="count++">Увеличить</button>
    <span x-text="count"></span>
    <span x-text="'Привет, ' + name"></span>
    <div x-show="count > 5">Число больше 5!</div>
</div>

Что не поддерживается⚓︎

Некоторые расширенные возможности JavaScript не будут работать в CSP-безопасном режиме:

Сложные JavaScript-выражения⚓︎

<!-- Это не работает -->
<button wire:click="items.filter(i => i.active).length">Подсчёт только активных?</button>
<div wire:show="users.some(u => u.role === 'admin')">Есть права админа?</div>
<button wire:click="(() => console.log('Hi'))()">Сложная функция</button>

Шаблонные литералы и расширенный синтаксис⚓︎

<!-- Это не работает -->
<div x-text="`Hello ${name}`">Плохо</div>
<div x-data="{ ...defaults }">Плохо</div>
<button x-on:click="() => doSomething()">Плохо</button>

Динамический доступ к свойствам⚓︎

<!-- Это не работает -->
<div wire:show="user[dynamicProperty]">Плохо</div>
<button wire:click="this[methodName]()">Плохо</button>

Обход ограничений⚓︎

Для сложных выражений Alpine используйте Alpine.data() или перенесите логику в методы:

<!-- Вместо сложных встроенных выражений -->
<div x-data="users">
    <div x-show="hasActiveAdmins">Админка доступна</div>
    <span x-text="activeUserCount">0</span>
</div>

<script nonce="[nonce]">
    Alpine.data('users', () => ({
        users: ...,

        get hasActiveAdmins() {
            return this.users.filter(u => u.active && u.role === 'admin').length > 0;
        },

        get activeUserCount() {
            return this.users.filter(u => u.active).length;
        }
    }));
</script>

Пример заголовков CSP⚓︎

Вот пример заголовков CSP, которые работают с CSP-безопасной сборкой Livewire:

Content-Security-Policy: default-src 'self';
                        script-src 'nonce-[random]' 'strict-dynamic';
                        style-src 'self' 'unsafe-inline';

Ключевые моменты:

  • Удалите 'unsafe-eval' из директивы script-src
  • Используйте загрузку скриптов на основе nonce с 'nonce-[random]'
  • Рассмотрите возможность добавления 'strict-dynamic' для лучшей совместимости с динамически загружаемыми скриптами

Рекомендации по производительности⚓︎

CSP-безопасная сборка использует другой вычислитель выражений, который:

  • Парсинг: чуть более медленный начальный парсинг выражений (обычно незначительно)
  • Время выполнения: аналогичная производительность во время выполнения для простых выражений
  • Размер бандла: немного больший размер JavaScript-бандла из-за кастомного парсера

Для большинства приложений эти различия незаметны, но стоит провести тестирование в вашем конкретном случае.

Тестирование вашей реализации CSP⚓︎

Чтобы убедиться, что ваша настройка CSP работает:

  1. Включите заголовки CSP на вашем веб-сервере или в приложении
  2. Проверьте в инструментах разработчика браузера — нарушения CSP появятся в консоли
  3. Убедитесь, что выражения работают — все ваши выражения Livewire и Alpine должны функционировать нормально
  4. Проверьте на наличие ошибок в консоли — не должно появляться никаких нарушений unsafe-eval

Когда использовать CSP-безопасный режим⚓︎

Рассмотрите возможность использования CSP-безопасного режима, когда:

  • Ваше приложение требует строгого соответствия CSP
  • Вы создаете приложения для сред с высокими требованиями к безопасности
  • Политики безопасности вашей организации запрещают 'unsafe-eval'
  • Вы развёртываете приложение на платформах с обязательными ограничениями CSP