Даты сами по себе редко воспринимаются как источник угрозы, однако в веб-приложениях они часто становятся частью динамического HTML, формируемого на стороне клиента. Именно на этом этапе возникает класс уязвимостей XSS (Cross-Site Scripting), когда результат форматирования даты оказывается внедрённым в DOM без должной изоляции.
Основная проблема заключается не в самой библиотеке обработки дат, а в цепочке: входные данные → парсинг даты → форматирование → вставка в HTML. Любое звено этой цепочки может превратить безобидную дату в носитель вредоносного кода, если оно реализовано неправильно.
В JavaScript дата часто приходит из внешних источников:
Типичный сценарий опасности возникает, когда дата не является строго валидированным ISO-значением, а представляет собой строку, которую затем форматируют через Day.js и вставляют в HTML.
Опасность усиливается, если исходная строка содержит неожиданные символы или HTML-подобные конструкции, например:
{
"createdAt": "<img src=x oner ror=alert(1)>"
}
Если такая строка проходит без фильтрации и затем отображается через DOM-интерполяцию, она становится полноценным XSS-вектором.
Наиболее распространённый источник проблем — использование результата
форматирования даты напрямую в innerHTML.
const formatted = dayjs(userInput).format('DD.MM.YYYY');
element.innerHTML = formatted;
Сам Day.js не выполняет интерпретацию HTML и не генерирует скрипты, однако уязвимость появляется из-за того, что результат помещается в HTML-контекст без экранирования.
Дополнительный риск возникает при конкатенации строк:
element.innerHTML = "Дата: " + dayjs(userInput).format('YYYY-MM-DD');
Даже если формат строго контролируется, опасность сохраняется при подмене входных данных или ошибках парсинга.
Day.js оперирует строго строками и объектами Date, не создавая DOM-структур и не интерпретируя HTML. Это делает библиотеку безопасной на уровне вычислений, но не на уровне отображения.
Ключевой принцип:
Day.js не защищает от XSS — он только формирует данные для отображения.
Безопасность определяется тем, как результат используется в UI.
Корректная архитектура работы с датами предполагает строгое разделение этапов:
Пример безопасного подхода:
const parsed = dayjs(userInput, 'YYYY-MM-DD', true);
if (parsed.isValid()) {
const output = parsed.format('DD.MM.YYYY');
element.textContent = output;
}
Ключевой момент — использование textContent вместо
innerHTML. Это исключает интерпретацию любых символов как
HTML.
Day.js поддерживает строгий режим парсинга при использовании плагина
customParseFormat.
import customParseFormat from 'dayjs/plugin/customParseFormat';
dayjs.extend(customParseFormat);
const parsed = dayjs(input, 'YYYY-MM-DD', true);
Строгий режим исключает невалидные строки, которые могут содержать посторонние символы или неожиданные конструкции.
Важно учитывать, что слабый парсинг может интерпретировать мусорные строки как валидные даты, что увеличивает поверхность атаки.
Форматирование через Day.js не является опасным само по себе:
dayjs(date).format('DD.MM.YYYY')
Однако риск возникает при:
Пример опасной конструкции:
element.innerHTML = `<span>${dayjs(date).format('DD.MM.YYYY')}</span>`;
Хотя здесь нет прямого XSS, сама практика использования
innerHTML создаёт потенциальную точку расширения уязвимости
при изменении входных данных.
Day.js поддерживает локали, что влияет на текстовые представления дат:
dayjs.locale('ru');
dayjs().format('dddd, D MMMM');
Локализация может казаться безопасной, но становится рискованной при:
Особенно опасны случаи, когда формат строки приходит с сервера:
const format = userConfig.dateFormat;
dayjs(date).format(format);
Если формат не ограничен whitelist-ом, возможны неожиданные сценарии отображения, включая вставку небезопасных символов в DOM-контекст.
При работе с результатами Day.js безопасные практики сводятся к контролю DOM-контекста.
Рекомендуемые подходы:
element.textContent = dayjs(date).format('YYYY-MM-DD');
Фреймворки автоматически экранируют строки:
<span>{dayjs(date).format('DD.MM.YYYY')}</span>
// небезопасно при любых внешних данных
element.innerHTML = formattedDate;
Наиболее частый источник XSS через даты — неконтролируемые API-ответы. Даже если API формально возвращает дату, фактически это может быть строка произвольного содержания.
Пример уязвимого сценария:
fetch('/api/data')
.then(r => r.json())
.then(data => {
const date = dayjs(data.date).format('DD.MM.YYYY');
element.innerHTML = date;
});
Если data.date подменён, результат форматирования
становится частью HTML-инъекции.
Корректная версия:
const parsed = dayjs(data.date, dayjs.ISO_8601, true);
if (parsed.isValid()) {
element.textContent = parsed.format('DD.MM.YYYY');
}
Безопасная обработка дат требует жёсткой нормализации:
ISO-строки минимизируют вероятность скрытых инъекций:
dayjs('2026-05-23T10:00:00Z')
Любые отклонения от стандарта увеличивают риск появления нестандартных интерпретаций.
XSS через даты не является свойством Day.js. Он возникает исключительно из-за контекста использования результата:
innerHTML)setAttribute)Даже строго отформатированная дата становится уязвимой, если попадает в неподходящий контекст.
Пример опасного использования в атрибуте:
element.setAttribute('data-date', dayjs(date).format());
Если атрибут затем интерпретируется как HTML в другом месте, цепочка уязвимости замыкается.
Безопасная работа с датами строится на принципе изоляции:
Day.js в этой модели выполняет роль чистого преобразователя данных, а защита реализуется на уровне UI-слоя и политики вставки в DOM.