Безопасная загрузка данных

Библиотека Globalize построена вокруг данных CLDR (Unicode Common Locale Data Repository). Эти данные включают правила форматирования чисел, дат, валют, склонения, множественные формы и прочие региональные особенности. В отличие от монолитных решений, Globalize сознательно разделяет код и данные, что делает вопрос безопасной загрузки критически важным.

Ключевая особенность архитектуры — отсутствие встроенных локалей. Разработчик сам отвечает за поставку данных. Это создаёт гибкость, но одновременно открывает поверхность атаки, если данные подгружаются без контроля.

Основной принцип:

Любые данные локализации следует считать внешними и потенциально недоверенными, даже если они приходят из собственного CDN


Источники данных и уровни доверия

Типичная схема работы включает несколько источников:

1. Статические JSON-файлы CLDR

Обычно поставляются через npm-пакеты или сборку:

  • cldr-numbers-full
  • cldr-dates-full
  • cldr-core

Эти данные считаются высокодоверенными, если:

  • загружены на этапе сборки (build-time)
  • проходят контроль версий
  • хэшируются в процессе сборки

2. Динамическая загрузка через HTTP/CDN

Используется для:

  • уменьшения размера бандла
  • поддержки множества локалей
  • lazy-loading языков

Этот путь считается среднедоверенным, поскольку:

  • возможна подмена CDN
  • возможны атаки через компрометированный источник
  • возможно вмешательство на уровне прокси

3. Пользовательские или внешние локали

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

  • плагины
  • сторонние сервисы
  • runtime-конфигурации от пользователя

Такие данные должны рассматриваться как небезопасные по умолчанию


Опасности при загрузке локализационных данных

Подмена числовых и валютных форматов

Если атакующий изменяет CLDR-данные, возможны:

  • неверное отображение валютных символов
  • подмена разделителей тысяч/десятичных
  • манипуляции с отображением сумм

Это не просто UI-баг, а потенциальная финансовая уязвимость.


Инъекции через строковые форматы

Хотя Globalize не выполняет код из данных, опасность возникает на уровне приложения:

  • данные могут попадать в DOM
  • форматированные строки могут быть вставлены через innerHTML
  • локализованные сообщения могут содержать HTML

Поломка логики парсинга

Изменённые правила могут привести к:

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

Принципы безопасной загрузки

1. Иммутабельность локализационных данных

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

  • заморозка объектов (Object.freeze)
  • отказ от runtime-мутаций
  • изоляция модулей локалей

Пример подхода:

  • локали собираются в build-step
  • результат включается в финальный бандл
  • runtime не имеет права их изменять

2. Версионирование CLDR

Любая версия CLDR должна быть зафиксирована:

  • запрещены диапазоны зависимостей
  • исключены автообновления без проверки
  • требуется контроль совместимости с Globalize

Важно учитывать:

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

3. Контроль источников загрузки

При динамической загрузке:

  • разрешён только whitelist доменов
  • применяется HTTPS обязательно
  • исключается загрузка с произвольных URL

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

  • Content Security Policy (CSP)
  • Subresource Integrity (SRI) для статических файлов
  • защита от DNS spoofing через pinned endpoints

4. Сборка локалей на этапе build-time

Наиболее безопасная стратегия:

  • загрузка CLDR через npm
  • генерация локалей в build pipeline
  • упаковка в JS/JSON артефакты

Преимущества:

  • отсутствие сетевой зависимости в runtime
  • предсказуемость поведения
  • возможность аудита данных

5. Изоляция слоя форматирования

Функции Globalize должны быть отделены от UI:

  • форматирование чисел и дат не должно напрямую возвращать HTML
  • результаты должны быть строками без разметки
  • HTML-рендеринг выполняется отдельно

Это снижает риск:

  • XSS через локализованные строки
  • подмены структуры DOM

Безопасная загрузка через модульную архитектуру

Типичная безопасная схема:

  1. Импорт ядра Globalize

  2. Загрузка CLDR core данных

  3. Подключение нужных модулей:

    • numbers
    • dates
    • currencies
  4. Инициализация локали

  5. Фиксация состояния

Критически важно, чтобы порядок инициализации был неизменяемым. Любое частичное подключение может привести к неконсистентному состоянию форматирования.


Проверка целостности данных

При загрузке через сеть применяются механизмы:

Hash-based verification

  • SHA-256 для JSON-ресурсов
  • проверка перед парсингом
  • отказ при несовпадении

Schema validation

  • проверка структуры CLDR JSON
  • валидация типов полей
  • контроль обязательных ключей

Runtime sanity checks

  • тестовые форматирования после загрузки

  • проверка базовых сценариев:

    • форматирование числа 1000
    • форматирование даты
    • формат валюты

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

Динамическая загрузка локали требует строгого пайплайна:

  • запрос локали
  • проверка источника
  • загрузка JSON
  • валидация структуры
  • регистрация в Globalize
  • активация локали

Любое отклонение должно приводить к:

  • отказу загрузки
  • fallback на дефолтную локаль (например, en)

Fallback-стратегии

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

  • отсутствие локали → переход на базовую
  • повреждённые CLDR данные → игнорирование пакета
  • частичная загрузка → откат к предыдущей версии

Fallback не должен зависеть от сети.


Опасные анти-паттерны

Использование eval-подобных механизмов

Даже косвенное выполнение строк из локализационных данных недопустимо.


Прямая вставка форматированных строк в HTML

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

  • element.innerHTML = Globalize.formatMessage(data)

Правильный подход:

  • textContent вместо innerHTML

Загрузка локалей без фиксации версии

Любой “latest” endpoint создаёт риск непредсказуемого поведения.


Доверие пользовательским локалям

Если система позволяет пользователю загружать собственные правила форматирования, это должно:

  • выполняться в sandbox
  • не влиять на глобальное состояние
  • не пересекаться с системными локалями

Контроль в браузерной среде

В браузере безопасность усиливается дополнительными механизмами:

  • CSP ограничивает загрузку скриптов и JSON
  • module script integrity предотвращает подмену модулей
  • CORS исключает доступ к произвольным источникам

Важно учитывать, что JSON-локали могут быть таким же вектором атаки, как и JavaScript.


Контроль в Node.js среде

В серверной среде отсутствуют браузерные ограничения, поэтому усиливаются:

  • контроль файловой системы
  • фиксация npm-версий
  • использование lock-файлов (package-lock.json, pnpm-lock.yaml)
  • аудит зависимостей

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

  • запрет динамической загрузки локалей с внешних URL без прокси-валидации

Поведение при частично повреждённых данных

Globalize может продолжать работу при неполных данных, но это должно быть управляемым:

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

Недопустимо:

  • молчаливое использование некорректных значений
  • автоматическое “догадывание” правил

Модель доверенной границы данных

Архитектурно данные локализации должны проходить три границы:

  1. Transport layer

    • HTTPS
    • SRI
    • проверка источника
  2. Validation layer

    • schema check
    • hash check
    • version check
  3. Application layer

    • иммутабельность
    • изоляция
    • безопасное использование в форматировании

Только после прохождения всех уровней данные считаются пригодными для использования в Globalize.