Content Security Policy

Content Security Policy (CSP) в контексте использования Tom Select напрямую влияет на то, будет ли компонент работать корректно в браузере при строгих настройках безопасности. Tom Select активно взаимодействует с DOM, динамически создаёт элементы интерфейса, вставляет HTML-разметку в dropdown, использует inline-стили и обработчики событий. При неверной конфигурации CSP это приводит к блокировке рендеринга, ошибкам в консоли и частичной или полной неработоспособности селекта.

Tom Select работает поверх стандартного <select> или заменяет его полностью, создавая собственную структуру:

  • контейнер выбора
  • выпадающий список
  • элементы опций
  • поисковую строку
  • теги выбранных значений

Каждый из этих элементов создаётся через JavaScript. Это означает, что CSP должен разрешать:

  • выполнение скриптов (script-src)
  • создание DOM-структур
  • вставку HTML через innerHTML
  • иногда inline-стили
  • обработку событий ввода

Главный риск — XSS через данные опций, если они приходят с сервера и не проходят санитизацию.


Базовая CSP-конфигурация для работы Tom Select

Стандартная политика, при которой Tom Select функционирует без ограничений:

Content-Security-Policy:
  default-src 'self';
  script-src 'self';
  style-src 'self' 'unsafe-inline';
  img-src 'self' dat a:;

Критический момент здесь — 'unsafe-inline' в style-src. Tom Select часто добавляет inline-стили для позиционирования dropdown и вычисления размеров. Без этого разрешения визуальная часть может ломаться: список не открывается, позиционирование становится некорректным или элементы оказываются скрытыми.


Проблемы при запрете inline-стилей

При более строгой политике:

style-src 'self';

наблюдаются следующие эффекты:

  • выпадающий список может открываться, но не позиционироваться
  • подсветка выбранных элементов исчезает
  • анимации и transition не работают
  • элементы становятся «слепыми» из-за отсутствия computed styles

Tom Select не полностью зависит от inline-стилей, но часть логики позиционирования и визуальной корректировки использует динамическое присвоение style через JavaScript.


Script-src и ограничения выполнения кода

Минимально безопасная конфигурация:

script-src 'self';

Tom Select не требует inline script execution, однако проблемы возникают в следующих случаях:

  • использование CDN-версии без добавления домена в CSP
  • подключение через eval-подобные конструкции в старых сборках
  • использование плагинов, генерирующих динамический код

Если библиотека подключается через CDN:

script-src 'self' https://cdn.jsdelivr.net;

Любое несоответствие приводит к полной блокировке и ошибке:

Refused to load the script because it violates Content Security Policy


Работа с HTML в опциях и CSP

Tom Select позволяет рендерить кастомные шаблоны:

new TomSelect("#select", {
  render: {
    option: function(data, escape) {
      return `<div>${data.text}</div>`;
    }
  }
});

В этом контексте CSP не блокирует сам шаблон, но вступает в конфликт с XSS-защитой, если:

  • используется innerHTML без экранирования
  • данные приходят с сервера и содержат HTML
  • отключено 'unsafe-eval' или 'unsafe-inline' при сложных шаблонах

Правильный подход — использование функции escape:

render: {
  option: function(data, escape) {
    return `<div>${escape(data.text)}</div>`;
  }
}

Функция escape экранирует HTML-символы, предотвращая внедрение скриптов.


CSP и XSS-риски через Tom Select

Наиболее частая проблема возникает при динамических данных:

{
  "value": "1",
  "text": "<img src=x oner ror=alert(1)>"
}

Если CSP ослаблена или отсутствует sanitization, Tom Select может вставить этот HTML в DOM.

Даже при наличии CSP:

script-src 'self'

XSS всё ещё возможен через:

  • innerHTML
  • insertAdjacentHTML
  • шаблоны без экранирования

CSP лишь ограничивает выполнение скриптов, но не предотвращает вставку HTML как таковую.


Рекомендованная схема защиты данных

Защита должна быть многоуровневой:

1. Санитизация на сервере

Удаление потенциально опасных тегов:

  • <script>
  • onerror, onclick
  • iframe, object

2. Экранирование на клиенте

Обязательное использование:

escape(data.text)

3. CSP как дополнительный слой

Content-Security-Policy:
  default-src 'self';
  script-src 'self';
  style-src 'self' 'unsafe-inline';
  object-src 'none';
  base-uri 'self';

Особенности Tom Select при строгом CSP (без unsafe-inline)

При попытке полного запрета inline-стилей:

style-src 'self';

необходимо компенсировать поведение через:

  • внешние CSS классы
  • переопределение render функций
  • отказ от динамического позиционирования

Пример кастомного класса:

new TomSelect("#select", {
  controlClass: "ts-control",
  dropdownClass: "ts-dropdown"
});

И CSS:

.ts-dropdown {
  position: absolute;
  z-index: 1000;
}

Однако даже в этом случае часть динамических вычислений размеров может нарушаться, так как Tom Select в ряде случаев всё равно устанавливает inline style через JavaScript.


CSP и события внутри Tom Select

Tom Select использует обработчики событий:

  • keydown
  • click
  • focus
  • blur

Они не конфликтуют с CSP напрямую, но становятся проблемными при:

script-src 'nonce-...'

Если используется nonce-based CSP, необходимо убедиться, что:

  • основной скрипт библиотеки подписан nonce
  • инициализация выполняется в разрешённом контексте

Иначе библиотека может загрузиться, но не инициализироваться.


Integrations: CSP + AJAX загрузка данных

Tom Select часто используется с remote data:

new TomSelect("#select", {
  load: function(query, callback) {
    fetch("/api/search?q=" + encodeURIComponent(query))
      .then(res => res.json())
      .then(callback);
  }
});

CSP в этом случае должен учитывать:

connect-src 'self';

Если API находится на другом домене:

connect-src 'self' https://api.example.com;

Иначе запросы будут заблокированы браузером, и dropdown не будет получать данные.


Частые ошибки при CSP и Tom Select

Ошибка 1: блокировка inline-стилей

Причина: отсутствует 'unsafe-inline' в style-src.

Ошибка 2: блокировка CDN скрипта

Причина: не добавлен домен CDN в script-src.

Ошибка 3: пустой dropdown

Причина: блокировка connect-src при AJAX загрузке.

Ошибка 4: сломанный UI

Причина: CSP запрещает inline style, а Tom Select не имеет CSS-альтернативы для части вычислений.


Баланс между безопасностью и функциональностью

Tom Select лучше всего работает при умеренно строгой CSP, где:

  • скрипты ограничены 'self' и доверенными CDN
  • стили допускают 'unsafe-inline'
  • соединения явно разрешены через connect-src
  • данные проходят экранирование на уровне приложения

Попытки полностью исключить inline-стили без переработки рендера обычно приводят к необходимости форкать поведение компонента или заменять его кастомной реализацией dropdown-механики.


Архитектурный подход к CSP-совместимости

В крупных приложениях Tom Select часто включается в систему с централизованной политикой безопасности:

  • единый CSP header на уровне backend
  • строгая санитизация API-ответов
  • ограничение render-логики компонентов
  • отказ от HTML в данных (только plain text)

Такой подход снижает необходимость компромиссов в CSP и уменьшает зависимость от 'unsafe-inline'.


Поведение браузеров при конфликте CSP и Tom Select

При нарушениях CSP браузеры:

  • блокируют выполнение скриптов до инициализации компонента
  • запрещают вставку inline-стилей
  • логируют ошибки в консоль безопасности
  • могут частично отрисовать DOM без функциональности

Tom Select в таких условиях остаётся в состоянии «неинициализированного select», где оригинальный <select> может быть скрыт, а UI-компонент не активирован.