Санитизация данных

Санитизация данных в контексте Pikaday заключается в обеспечении корректности, предсказуемости и безопасности всех значений, которые проходят через API календаря и взаимодействуют с DOM-элементами, форматтерами и пользовательским вводом. Основной источник рисков связан с тем, что библиотека оперирует строковыми представлениями дат, форматами отображения и внешними callback-функциями, которые могут содержать потенциально небезопасные данные.

Pikaday принимает конфигурационные параметры, среди которых ключевыми для санитизации являются defaultDate, setDefaultDate, minDate, maxDate, disableDayFn, format, toString, parse. Любое значение даты, передаваемое в эти параметры, должно приводиться к строго определённому типу Date или валидной строке, которая однозначно парсится.

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

  • неоднозначные форматы дат (01-02-03)
  • локализованные строки ("10 января 2025")
  • пользовательские строки из input без предварительной проверки

Стратегия санитизации включает явное преобразование:

function sanitizeDate(input) {
  const date = new Date(input);
  return isNaN(date.getTime()) ? null : date;
}

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

Нормализация входного поля input

Pikaday тесно связан с DOM input-элементом. Значение поля может быть изменено внешними скриптами, автозаполнением или ручным вводом. Санитизация здесь включает:

  • удаление недопустимых символов
  • приведение строки к ожидаемому формату
  • проверку на соответствие формату перед парсингом
function normalizeInputValue(value) {
  return value.replace(/[^\d\-\/\.]/g, '').trim();
}

После нормализации выполняется парсинг через parse-функцию Pikaday, если она задана, либо через стандартный конструктор Date.

Защита от XSS через форматирование

Особое внимание требует параметр toString, отвечающий за отображение даты. Если он реализован без санитизации, возможно внедрение HTML/JS-инъекций через DOM-манипуляции.

Опасный сценарий:

toString(date) {
  return `<img src=x oner ror=alert(1)>`;
}

Pikaday вставляет результат в input как строку, но при использовании сторонних UI-обёрток или кастомных рендеров это может привести к выполнению скриптов.

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

toString(date, format) {
  return date instanceof Date
    ? date.toISOString().split('T')[0]
    : '';
}

Ключевой принцип — отсутствие HTML-разметки в возвращаемом значении.

Санитизация пользовательского формата

Параметр format часто становится источником логических уязвимостей. Хотя Pikaday не интерпретирует формат как код, некорректная обработка может привести к:

  • путанице при парсинге
  • некорректной интерпретации даты
  • несогласованности между отображением и внутренним состоянием

Санитизация формата включает whitelist-подход:

const ALLOWED_TOKENS = ['DD', 'MM', 'YYYY', 'YY'];

function sanitizeFormat(format) {
  return format
    .split(/[^A-Za-z]/)
    .filter(token => ALLOWED_TOKENS.includes(token))
    .join('-');
}

Такая фильтрация устраняет произвольные строки, которые могут нарушить логику отображения.

Обработка функции parse

Функция parse является одной из наиболее чувствительных точек, поскольку позволяет полностью переопределить логику преобразования строки в дату. Неправильная реализация может привести к:

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

Корректная санитизация требует:

  • обязательной проверки результата на Date
  • проверки диапазонов дат
  • отказа при некорректных значениях
parse(input, format) {
  const parsed = customParseLogic(input, format);

  if (!(parsed instanceof Date) || isNaN(parsed.getTime())) {
    return null;
  }

  return parsed;
}

Валидация диапазонов дат

Параметры minDate и maxDate требуют строгой проверки логической согласованности. Санитизация включает:

  • проверку порядка дат
  • нормализацию времени до начала суток
  • устранение временных зон, влияющих на сравнение
function sanitizeRange(minDate, maxDate) {
  if (minDate && maxDate && minDate > maxDate) {
    const temp = minDate;
    minDate = maxDate;
    maxDate = temp;
  }

  return { minDate, maxDate };
}

Очистка callback-функций

Pikaday поддерживает onSelect, onOpen, onClose. Хотя это не данные в классическом смысле, callback-и могут быть источником побочных эффектов, если принимают внешние значения без проверки.

Санитизация входных аргументов callback:

onSelect(date) {
  if (!(date instanceof Date) || isNaN(date.getTime())) {
    return;
  }

  handleValidDate(date);
}

Защита от прототипных атак

При работе с объектом конфигурации Pikaday возможны ситуации, когда передаются небезопасные объекты с изменённым прототипом. Санитизация включает создание «чистого» объекта:

function sanitizeConfig(config) {
  return Object.assign(Object.create(null), config);
}

Это устраняет влияние __proto__ и предотвращает модификацию цепочки прототипов.

Обработка локализации

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

const allowedKeys = ['previousMonth', 'nextMonth', 'months', 'weekdays'];

function sanitizeI18n(i18n) {
  const clean = {};

  for (const key of allowedKeys) {
    if (typeof i18n[key] === 'string' || Array.isArray(i18n[key])) {
      clean[key] = i18n[key];
    }
  }

  return clean;
}

Нормализация состояния календаря

Внутреннее состояние Pikaday зависит от текущей выбранной даты, отображаемого месяца и года. Санитизация состояния включает:

  • проверку корректности месяца (0–11)
  • проверку диапазона года
  • синхронизацию даты и отображаемого календаря
function sanitizeState(state) {
  if (state.month < 0 || state.month > 11) state.month = 0;
  if (state.year < 1970) state.year = 1970;

  return state;
}

Обработка внешних источников данных

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

  • ISO 8601 как базовый формат
  • отказ от локализованных строк
  • проверка временных зон
function sanitizeExternalDate(value) {
  const date = new Date(value);
  if (isNaN(date.getTime())) return null;
  return new Date(date.toISOString());
}

Итоговая модель безопасного потока данных

Вся цепочка обработки данных в Pikaday должна строиться по принципу:

  1. получение входного значения
  2. нормализация строки или объекта
  3. строгая валидация типа Date
  4. проверка диапазонов
  5. преобразование в отображаемый формат
  6. вывод только текстовых значений без HTML

Такая последовательность устраняет основные классы ошибок: XSS, некорректный парсинг, нарушение диапазонов и прототипные загрязнения.