Защита от XSS через SVG

SVG-рендеринг в Lottie Web основан на динамическом создании DOM-дерева, где каждая анимационная сущность преобразуется в SVG-элементы (<path>, <g>, <mask>, <image> и т.д.). В отличие от Canvas-рендерера, SVG остаётся частью DOM и наследует все свойства веб-страницы: события, атрибуты, политики безопасности и потенциальные точки внедрения скриптового кода.

Ключевая особенность SVG как вектора в DOM — возможность содержать активные конструкции. Это делает его естественной зоной риска при работе с любыми внешними или частично доверенными источниками анимации.


Основные векторы XSS в SVG

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

Обработчики событий

В SVG допустимы inline-обработчики:

  • onload
  • onerror
  • onbegin
  • onrepeat

Пример потенциально опасной конструкции:

<svg>
  <script>alert(1)</script>
  <image oner ror="alert(1)" />
</svg>

Даже если прямые <script> блоки блокируются, события остаются значимым каналом.


SVG поддерживает ссылки через href и устаревший xlink:href. При некорректной фильтрации возможно внедрение:

  • jav * ascript: URI
  • data URI с HTML/JS содержимым

<foreignObject> и HTML-инъекция

foreignObject позволяет внедрять HTML внутри SVG:

<foreignObject>
  <div xmlns="http://www.w3.org/1999/xhtml">
    <img src="x" oner ror="alert(1)" />
  </div>
</foreignObject>

Это один из наиболее опасных механизмов, так как переносит атаку из SVG в полноценный HTML-рендеринг.


CSS-инъекции внутри SVG

SVG поддерживает встроенные стили:

<style>
  @import url("jav * ascript:alert(1)");
</style>

Также возможно использование url() с внешними ресурсами, приводящее к утечкам данных или загрузке вредоносного контента.


Lottie Web и точка входа SVG

Библиотека Lottie Web (bodymovin) поддерживает несколько рендереров:

  • svg
  • canvas
  • html

SVG-режим наиболее уязвим, поскольку строит интерактивное DOM-дерево.

Основные точки загрузки данных:

lottie.loadAnimation({
  container: element,
  renderer: 'svg',
  path: 'animation.json'
});

или

lottie.loadAnimation({
  container: element,
  renderer: 'svg',
  animationData: data
});

Угроза возникает не из самого API, а из источника animationData или удалённого JSON.


Доверенные и недоверенные источники данных

Критическая граница безопасности проходит по источнику JSON-анимации:

Доверенный источник

  • локально сгенерированный JSON (After Effects pipeline)
  • сервер с контролируемым CI/CD
  • подписанные артефакты

Недоверенный источник

  • пользовательские загрузки
  • внешние CDN без контроля
  • динамические API без валидации

SVG-рендерер не различает происхождение данных — он только интерпретирует структуру.


Потенциальные уязвимости внутри структуры Lottie JSON

Хотя Lottie формально использует JSON, внутри него могут присутствовать конструкции, влияющие на SVG:

Изображения (assets)

Поле p может указывать на внешние ресурсы:

  • удалённые изображения
  • data URI
  • неконтролируемые URL

Это создаёт риск SSRF-подобного поведения на клиенте и утечек через загрузку ресурсов.


Маски и режимы наложения

Некоторые SVG-маски могут комбинироваться с внешними изображениями, создавая возможность:

  • утечки через timing attacks
  • загрузки внешних ресурсов без ведома приложения

Expressions (After Effects expressions)

Хотя expressions обычно вычисляются до экспорта, некоторые пайплайны могут сохранять динамические вычисления. В случае неправильной обработки:

  • возможна подстановка небезопасных значений
  • инъекция в атрибуты SVG

Методы защиты на уровне рендерера

1. Использование Canvas вместо SVG

Наиболее надёжный способ устранения SVG-XSS класса угроз:

lottie.loadAnimation({
  container: element,
  renderer: 'canvas',
  animationData: data
});

Canvas полностью исключает DOM-инъекции, так как вывод представляет собой пиксельный буфер.


2. Санитизация SVG-дерева

Если SVG обязателен, необходимо фильтровать результат до вставки в DOM.

Подходы:

  • удаление всех on* атрибутов
  • блокировка <script>
  • запрет <foreignObject>
  • ограничение href схем

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

  • whitelist тегов: path, g, rect, circle, defs
  • whitelist атрибутов: d, fill, stroke, transform

3. Использование DOMPurify

DOMPurify с SVG-режимом позволяет минимизировать риск XSS:

DOMPurify.sanitize(svgString, {
  USE_PROFILES: { svg: true }
});

Дополнительные ограничения:

  • FORBID_TAGS: ['foreignObject', 'script']
  • FORBID_ATTR: [/^on/i]

4. Content Security Policy (CSP)

CSP снижает ущерб даже при успешной инъекции:

  • запрет inline script
  • запрет unsafe-eval
  • ограничение img-src, object-src, media-src

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

  • script-src 'self'
  • object-src 'none'
  • base-uri 'none'

5. Контроль загрузки внешних ресурсов

SVG-рендерер может инициировать запросы к:

  • изображениям
  • шрифтам
  • внешним маскам

Необходимо:

  • проксировать ресурсы
  • проверять URL по whitelist
  • блокировать data: и jav * ascript: схемы

Изоляция Lottie-анимации

Для минимизации последствий компрометации SVG-рендерера применяются архитектурные подходы:

iframe sandbox

Изоляция в sandboxed iframe:

  • запрет скриптов
  • ограничение сетевого доступа
  • разделение origin

Shadow DOM

Использование Shadow DOM снижает риск утечки событий и упрощает контроль над стилями, но не устраняет SVG-XSS полностью.


Валидация Lottie JSON перед рендерингом

Перед передачей данных в Lottie Web выполняется строгая проверка:

  • структура JSON по схеме
  • отсутствие неожиданных ключей
  • проверка URL полей
  • ограничение глубины вложенности

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

  • лимит размера JSON
  • лимит количества слоёв (layers)
  • запрет неизвестных типов ty

Ограничение функциональности SVG-рендера

Практика безопасных конфигураций включает:

  • отключение масок при недоверенных данных
  • запрет gradients с внешними ссылками
  • ограничение blending modes
  • фильтрация filter эффектов

Архитектурный принцип доверия

SVG в Lottie Web должен рассматриваться как потенциально исполняемая среда, а не как статическая графика. Любая анимация:

  • интерпретируется как DOM
  • может содержать активные элементы
  • наследует поведение браузера

Граница безопасности проходит не между JSON и SVG, а между доверенным и недоверенным источником данных.


Практика безопасного пайплайна

Безопасный цикл обработки анимаций обычно включает:

  1. Создание в After Effects
  2. Экспорт через bodymovin
  3. Серверная валидация JSON
  4. Санитизация SVG (если используется SVG-рендерер)
  5. CSP на уровне приложения
  6. Отказ от inline-рендера для пользовательского контента

Типовые ошибки интеграции

  • прямое использование innerHTML для SVG-строки
  • загрузка animationData из пользовательских источников без проверки
  • использование SVG-рендера для контента, приходящего с CDN без контроля
  • отсутствие CSP в SPA-приложениях
  • смешивание доверенных и недоверенных анимаций в одном контейнере