Безопасность пользовательского контента

Визуализация карт в браузере объединяет несколько источников данных: пользовательский ввод, удалённые тайловые серверы, стили, GeoJSON, изображения и HTML-подобные всплывающие окна. Каждый из этих слоёв способен стать точкой внедрения вредоносного контента, если отсутствует строгая модель доверия и фильтрации данных.

Основной принцип безопасной архитектуры в картографических веб-приложениях заключается в том, что MapLibre GL JS выполняет только рендеринг, но не является источником доверия к данным. Любой входной объект — геоданные, стиль, подписи, свойства объектов — должен рассматриваться как потенциально недоверенный.


Модель доверия и границы контроля

При работе с картографическими данными важно разделять систему на три независимых слоя:

  • слой данных (GeoJSON, векторные тайлы, растровые тайлы)
  • слой стиля (Style Specification JSON)
  • слой представления (DOM-элементы, popup, marker)

Критическая ошибка проектирования — перенос доверия между слоями без проверки.

Например:

  • данные из GeoJSON не должны напрямую интерпретироваться как HTML
  • свойства объектов не должны становиться частью DOM без экранирования
  • удалённый style.json нельзя считать безопасным только потому, что он “от сервера”

Опасности пользовательского GeoJSON

GeoJSON часто используется как основной механизм передачи пользовательских объектов. Однако его свойства (properties) нередко становятся источником XSS-уязвимостей.

Типичные риски:

  • внедрение HTML/JS в properties.description
  • использование строк как источника DOM через popup.setHTML
  • подмена координат с целью перегрузки рендера или логических ошибок

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

  • прямое использование feature.properties.name внутри innerHTML
  • вставка необработанного содержимого в всплывающие окна

Безопасный подход заключается в том, что GeoJSON всегда считается недоверенным источником данных.

Рекомендуемые практики:

  • использовать textContent вместо innerHTML
  • экранировать строки перед вставкой в DOM
  • применять строгую валидацию схемы GeoJSON перед добавлением на карту

Всплывающие окна и DOM-инъекции

Popup-компоненты в MapLibre GL JS часто становятся основным вектором XSS.

Наиболее опасные сценарии:

  • использование setHTML() с пользовательскими строками
  • вставка сырых данных из API без фильтрации
  • генерация HTML на основе свойств feature без санитизации

Даже при отсутствии явного <script> возможно выполнение вредоносного кода через:

  • onerror в изображениях
  • onload в iframe
  • inline event handlers (onclick, onmouseover)
  • SVG-инъекции

Безопасная модель:

  • предпочтение setText()
  • если HTML необходим — использование санитайзеров (DOMPurify или аналогов)
  • запрет inline-атрибутов событий

Маркеры и кастомный DOM

Маркеры в MapLibre GL JS создаются через обычные DOM-элементы, что делает их уязвимыми при неправильной обработке данных.

Риски:

  • вставка пользовательского HTML в контейнер маркера
  • использование innerHTML для генерации иконок
  • динамическое подключение внешних ресурсов (изображений, SVG)

Особенно опасно:

  • генерация SVG из пользовательских строк
  • использование внешних URL без проверки

Рекомендуемая модель:

  • создание элементов через document.createElement
  • использование textContent
  • жёсткая фильтрация URL для изображений

Стиль (Style Specification) как потенциальный вектор атаки

Style JSON в MapLibre GL JS описывает всё поведение карты: источники данных, слои, фильтры, выражения.

Риски при работе с динамическими стилями:

  • подмена источников tile server URL
  • внедрение неконтролируемых sprite-ресурсов
  • использование сложных выражений для деградации производительности
  • утечка данных через неправильно настроенные источники

Особое внимание требуется к:

  • sources → любые URL должны проходить whitelist
  • glyphs → подмена шрифтовых серверов
  • sprite → загрузка внешних изображений
  • tiles → потенциальные SSRF-подобные сценарии

Ключевой принцип: style JSON должен считаться исполняемой конфигурацией, а не просто данными.


Риски выражений и фильтрации данных

MapLibre GL JS поддерживает выражения (expressions), которые позволяют вычислять визуальные параметры слоёв.

Хотя выражения безопаснее, чем произвольный JS, они всё равно могут использоваться для:

  • создания чрезмерно сложных вычислений (performance DoS)
  • обхода логики отображения данных
  • скрытия объектов через условные конструкции

Опасны:

  • вложенные case и match без ограничений
  • вычисления на больших массивах свойств
  • динамическая фильтрация на основе пользовательских данных

Рекомендация:

  • ограничивать сложность выражений на уровне серверной генерации стиля
  • валидировать style.json перед применением

Безопасность источников тайлов и CORS

Векторные и растровые тайлы загружаются из внешних источников, что создаёт сетевую поверхность атаки.

Основные угрозы:

  • подмена тайл-сервера (data poisoning)
  • SSRF через неправильно настроенные URL
  • утечка токенов через Referer
  • отсутствие CORS-защиты

Практики защиты:

  • использование HTTPS для всех tile endpoints
  • строгая настройка CORS на сервере
  • ограничение доменов через whitelist
  • использование токенов с ограниченным временем жизни

Шрифты, спрайты и внешние ресурсы

MapLibre GL JS загружает дополнительные ресурсы:

  • sprite sheets (иконки)
  • glyph ranges (шрифты)
  • изображения слоёв

Каждый из этих ресурсов может быть заменён злоумышленником при отсутствии контроля домена.

Риски:

  • подмена иконок интерфейса
  • внедрение фишинговых визуальных элементов
  • утечка пользовательской активности через запросы к внешним серверам

Защита:

  • хранение ресурсов только на доверенном домене
  • отказ от динамической подмены sprite/glyph URL на клиенте
  • кеширование и подпись ресурсов

Безопасная работа с пользовательскими стилями

При возможности загрузки пользовательских стилей необходимо рассматривать их как исполняемый код конфигурации.

Основные меры:

  • JSON Schema валидация style.json
  • ограничение доступных source типов
  • запрет произвольных URL
  • статический анализ слоёв перед применением

Дополнительно:

  • sandboxing стилей на серверной стороне
  • предварительный рендер в изолированной среде
  • контроль версий стиля

DOMPurify и стратегия санитизации

При необходимости отображения HTML-контента в popup или sidebar применяется стратегия очистки:

  • удаление всех inline event handlers
  • запрет <script>, <iframe>, <object>
  • фильтрация SVG опасных атрибутов
  • нормализация ссылок

Важно учитывать, что даже очищенный HTML остаётся потенциальным источником уязвимостей при неправильной конфигурации политик CSP.


Content Security Policy как обязательный слой защиты

CSP выступает последней линией обороны против XSS в картографических приложениях.

Рекомендуемые директивы:

  • запрет unsafe-inline
  • ограничение img-src и media-src
  • жёсткое определение connect-src для тайловых серверов
  • запрет script-src для сторонних доменов

Особенно важно:

  • блокировать выполнение inline JS
  • ограничивать загрузку SVG как изображений при необходимости

Логическая безопасность и подмена данных

Помимо классических XSS-рисков, картографические приложения подвержены логическим атакам:

  • подмена координат для искажения аналитики
  • массовая генерация объектов для перегрузки рендера
  • внедрение “невидимых” слоёв через прозрачность
  • манипуляция фильтрами отображения данных

Защита строится на серверной валидации геоданных до их передачи в клиент.


Изоляция и архитектурные ограничения

Наиболее устойчивые архитектуры используют следующие принципы:

  • клиент получает только валидированные и ограниченные данные
  • style.json генерируется сервером, а не пользователем
  • все внешние источники проходят через прокси
  • отсутствует прямой доступ к произвольным URL из клиента

MapLibre GL JS в таком подходе выступает исключительно как слой визуализации без принятия решений о доверии к данным.