Telegram Mini Apps (TMA) стали одним из самых быстрорастущих каналов продаж, клиентского обслуживания и Web3-сервисов в 2026 году. Построение веб-приложения внутри экосистемы Telegram позволяет мгновенно получать доступ к аутентифицированному пользователю без необходимости ввода логина и пароля.
Однако кажущаяся простота таит в себе серьезные риски безопасности. Злоумышленник может сэмулировать клиентское окружение Telegram, подделать объект пользователя window.Telegram.WebApp.initData и получить несанкционированный доступ к чужим балансам, персональным данным или админ-панели.
В этой статье эксперты по кибербезопасности из EvaLab детально разоберут архитектуру безопасной аутентификации Telegram Mini Apps с верификацией подписи HMAC-SHA256 на TypeScript.
Векторы атак и особенности архитектуры Telegram Mini Apps
Когда Telegram открывает ваше Mini App внутри iframe или встроенного WebView, он передает в URL или метод инициализации строку initData. Эта строка содержит сведения о пользователе (user), чате, времени создания строки (auth_date) и криптографический хэш (hash).
Главные угрозы при неверной реализации безопасности:
- Спуфинг (Spoofing): отправив запрос напрямую к вашему бэкенд API с чужим
telegram_idв JSON-теле, злоумышленник может выдать себя за любого пользователя или администратора. - Replay-атаки (Атаки повторного воспроизведения): если бэкенд верифицирует
initDataбез проверки времени жизниauth_date, перехваченная ранее подпись может использоваться бессрочно. - Man-in-the-Middle (MitM): отсутствие валидации и передача данных не по HTTPS.
Криптографический алгоритм подписи initData
Для проверки подлинности данных Telegram использует двухступенчатую схему хэширования на базе HMAC-SHA256:
- Создается ключ подписи
secret_keyпутем хэширования токена бота (bot_token) с постоянной строковой меткой"WebAppData": $$\text{secret_key} = \text{HMAC-SHA256}("WebAppData", \text{bot_token})$$ - Переданная строка
initDataразбивается на парыkey=value, сортируется по алфавиту по ключам (исключая сам параметрhash) и объединяется через символ перевода строки\n. Получается каноничная строкаdata_check_string. - Вычисляется итоговый HMAC-SHA256 от
data_check_stringс использованиемsecret_key: $$\text{calculated_hash} = \text{HMAC-SHA256}(\text{data_check_string}, \text{secret_key})$$ - Если
calculated_hashсовпадает с полученным изinitDataхешемhash, данные подлинны и сформированы самим Telegram.
Пошаговая реализация валидации initData на TypeScript (Node.js)
Реализуем модульный сервисный класс безопасности на Node.js с использованием встроенного модуля crypto:
import crypto from 'crypto';
export interface TelegramUser {
id: number;
first_name: string;
last_name?: string;
username?: string;
language_code?: string;
is_premium?: boolean;
}
export interface ValidatedInitData {
user: TelegramUser;
auth_date: number;
query_id?: string;
}
export class TelegramAuthService {
private botToken: string;
private maxAgeSeconds: number;
constructor(botToken: string, maxAgeSeconds: number = 86400) {
this.botToken = botToken;
this.maxAgeSeconds = maxAgeSeconds; // По умолчанию сессия валидна 24 часа
}
/**
* Валидирует initData и возвращает распаршенные данные пользователя
*/
public validateInitData(rawInitData: string): ValidatedInitData {
const urlParams = new URLSearchParams(rawInitData);
const hash = urlParams.get('hash');
if (!hash) {
throw new Error('Криптографический хэш (hash) отсутствует');
}
urlParams.delete('hash');
// 1. Сортировка пар ключ=значение в алфавитном порядке
const dataCheckArr: string[] = [];
urlParams.forEach((value, key) => {
dataCheckArr.push(`${key}=${value}`);
});
dataCheckArr.sort();
const dataCheckString = dataCheckArr.join('\n');
// 2. Расчет secret_key
const secretKey = crypto
.createHmac('sha256', 'WebAppData')
.update(this.botToken)
.digest();
// 3. Расчет контрольного хэша
const calculatedHash = crypto
.createHmac('sha256', secretKey)
.update(dataCheckString)
.digest('hex');
// 4. Безопасное сравнение строк для защиты от timing-атак
const isHashValid = crypto.timingSafeEqual(
Buffer.from(calculatedHash, 'hex'),
Buffer.from(hash, 'hex')
);
if (!isHashValid) {
throw new Error('Подпись initData недействительна. Данные подделаны!');
}
// 5. Проверка возраста подписи (Защита от Replay-атак)
const authDateStr = urlParams.get('auth_date');
if (!authDateStr) {
throw new Error('Отсутствует поле auth_date');
}
const authDate = parseInt(authDateStr, 10);
const currentTime = Math.floor(Date.now() / 1000);
if (currentTime - authDate > this.maxAgeSeconds) {
throw new Error('Срок действия сессии initData истек');
}
const userJson = urlParams.get('user');
if (!userJson) {
throw new Error('Объект пользователя отсутствует в initData');
}
return {
user: JSON.parse(userJson) as TelegramUser,
auth_date: authDate,
query_id: urlParams.get('query_id') || undefined,
};
}
}
[!CAUTION] Всегда используйте
crypto.timingSafeEqual()вместо стандартного оператора===при сравнении хэшей. Обычное сравнение строк уязвимо для атак по времени (Timing Attacks), позволяющих злоумышленнику подобрать хэш побайтово!
Сессионная безопасность и архитектура JWT
Постоянно передавать исходный initData в каждом HTTP-запросе к API неэффективно и небезопасно (увеличивается размер сетевых заголовков).
Рекомендуемый паттерн защиты API Telegram Mini App:
sequenceDiagram
autonumber
actor User as Telegram App (Frontend)
participant AuthAPI as Backend Auth API
participant DB as База Данных
participant AppAPI as Protected API
User->>AuthAPI: POST /api/auth/telegram (initData)
AuthAPI->>AuthAPI: Проверка HMAC-SHA256 & auth_date
AuthAPI->>DB: Upsert пользователя по telegram_id
AuthAPI-->>User: Выдача short-lived JWT (Access Token) + HttpOnly Refresh Cookie
User->>AppAPI: GET /api/user/orders (Header: Bearer JWT)
AppAPI-->>User: Ответ с данными заказа
- Эндпоинт авторизации (
/api/auth/telegram): принимаетinitData, выполняет верификацию HMAC-SHA256 и регистрирует/обновляет профиль пользователя в БД. - Выдача JWT-токена: сервер возвращает короткоживущий Access Token (время жизни 15–30 минут) и устанавливает Refresh Token в
HttpOnly, Secure, SameSite=StrictCookie. - Защита эндпоинтов: последующие API-запросы выполняются через стандартный заголовок
Authorization: Bearer <token>.
Чек-лист безопасности при запуске Telegram Mini App в продакшен
- Серверная валидация HMAC-SHA256 включена для всех входных точек.
- Настроена строго ограниченная проверка
auth_date(не старее 24 часов). - Используется безопасное сравнение
crypto.timingSafeEqual. - Токен бота (
BOT_TOKEN) хранится исключительно в переменной окружения сервера (.env.local) и никогда не попадает в JS-бандл фронтенда. - Настроены заголовки CORS, Content Security Policy (CSP) и защищенное соединение HTTPS.
- Реализован Rate Limiting на стороне бэкенда для защиты от брутфорса и DDOS-атак (например, через Redis / Upstash).
Заключение
Telegram Mini Apps — это мощнейший инструмент для развития B2B и B2C бизнеса, но его безопасность напрямую зависит от правильной реализации криптографической проверки initData. Небрежный подход к авторизации открывает критические уязвимости для взлома и утечки клиентских данных.
Нужна профессиональная и защищенная разработка Telegram Mini App, интеграция с платежными системами и бэкендом? Доверьте разработку экспертам EvaLab — мы гарантируем высокую безопасность и отказоустойчивость ваших сервисов!



