Безопасная интерполяция в i18next является ключевым механизмом защиты от внедрения вредоносного кода при подстановке динамических значений в переводы. Интерполяция в i18next используется повсеместно: подстановка имён пользователей, числовых значений, URL, фрагментов HTML и структурированных данных. Ошибки в её конфигурации приводят к XSS-уязвимостям, особенно в приложениях без дополнительного слоя экранирования.
Интерполяция основана на шаблонных выражениях внутри строк перевода:
{
"welcome": "Привет, {{name}}!"
}
При вызове:
i18next.t('welcome', { name: 'Алексей' })
результат:
Привет, Алексей!
Система заменяет {{name}} на переданное значение,
используя встроенный интерполяционный процессор.
Основной риск возникает при подстановке значений, содержащих HTML или Jav * aScript:
i18next.t('welcome', { name: '<img src=x oner ror=alert(1) />' })
Если экранирование отключено, результат попадёт в DOM как исполняемый HTML.
Это особенно опасно при использовании:
innerHTMLВ i18next интерполяция по умолчанию включает экранирование:
i18next.init({
interpolation: {
escapeValue: true
}
});
При включённом escapeValue символы:
<>&"'заменяются на HTML-сущности:
< → <
> → >
& → &
Таким образом:
i18next.t('welcome', { name: '<b>test</b>' })
становится:
Привет, <b>test</b>
и не интерпретируется браузером как HTML.
В некоторых конфигурациях встречается:
i18next.init({
interpolation: {
escapeValue: false
}
});
Это допустимо только при условии, что слой рендеринга уже обеспечивает защиту (например, React).
При использовании DOM напрямую:
element.innerHTML = i18next.t('welcome', { name })
отключение экранирования создаёт прямую XSS-уязвимость.
В React i18next экранирование часто отключается:
interpolation: {
escapeValue: false
}
Причина заключается в том, что React сам экранирует значения при рендеринге:
<div>{t('welcome', { name })}</div>
React преобразует значения в безопасный текстовый узел, предотвращая выполнение HTML.
Однако опасность возникает при использовании:
<div dangerouslySetInnerHTML={{ __html: t('welcome', { name }) }} />
В этом случае ответственность полностью переносится на i18next и входные данные.
i18next поддерживает вставку HTML-подобных структур через интерполяцию, например:
{
"message": "Нажми <strong>{{button}}</strong>"
}
При небезопасной конфигурации это может быть интерпретировано как HTML.
Для безопасной работы применяется разделение:
{{}}Более безопасный подход:
<Trans i18nKey="message">
Нажми <strong>{{button}}</strong>
</Trans>
Здесь React контролирует структуру DOM, а i18next не выполняет прямую HTML-инъекцию.
i18next позволяет переопределить механизм экранирования:
i18next.init({
interpolation: {
escapeValue: true,
escape: (value) => {
return value.replace(/[&<>"']/g, (char) => {
const map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return map[char];
});
}
}
});
Такой подход используется в средах, где требуется строгий контроль над процессом санитизации.
i18next поддерживает сложные структуры:
i18next.t('user.info', {
user: {
name: '<script>alert(1)</script>'
}
});
и ключ:
{
"user": {
"info": "Пользователь: {{user.name}}"
}
}
Без экранирования вложенные значения также становятся источником XSS.
Интерполяция может работать с форматированием:
i18next.t('price', {
value: 1234.56,
format: 'currency'
});
Безопасность здесь связана не только с XSS, но и с подменой данных при некорректной локализации.
На сервере интерполяция формирует HTML до передачи клиенту:
const html = i18next.t('page', { name });
Если данные не экранированы, вредоносный код попадает в исходный HTML ответа.
Особенно критично при:
Наиболее рискованные сценарии:
// небезопасно
element.innerHTML = i18next.t('key', data);
// небезопасно при escapeValue: false
i18next.t('key', { name: userInput });
// небезопасно при SSR без фильтрации
res.send(i18next.t('page', data));
Корректные подходы:
// безопасно с React
<div>{t('key', data)}</div>
// безопасно при escapeValue: true
i18next.t('key', data)
// безопасная структура через Trans
<Trans i18nKey="key">
<strong />
</Trans>
При работе с TypeScript важно учитывать типизацию значений:
i18next.t<{ name: string }>('welcome', {
name: user.name
});
Это снижает риск передачи неожиданных структур, которые могут привести к некорректной сериализации.
i18next позволяет ограничивать поведение интерполяции:
i18next.init({
interpolation: {
skipOnVariables: false,
defaultVariables: {
appName: 'MyApp'
}
}
});
Это помогает контролировать предсказуемость данных и снижает вероятность подмены значений.
Контекстная система:
i18next.t('button', { context: 'save' });
не влияет напрямую на безопасность, но может использоваться для обхода фильтров, если контекст формируется из пользовательского ввода.
Наиболее надёжный подход — очистка данных до передачи в i18next:
function sanitize(input) {
return input.replace(/</g, '').replace(/>/g, '');
}
i18next.t('welcome', {
name: sanitize(userInput)
});
Такой подход снижает нагрузку на механизм экранирования и исключает риск ошибок конфигурации.
i18next может интерполировать объекты:
i18next.t('key', { user: { name: 'Alex' } });
Если объект преобразуется в строку через toString(),
результат может быть неожиданным:
[object Object]
или содержать нежелательные данные при кастомных объектах.
Контроль сериализации предотвращает утечку структур и косвенные уязвимости.
innerHTML требуют строгого
контроляescapeValue допустимо только при
гарантированной внешней защите