// личный канал‑лог
gavrilovlog
← все записи

Телеграм как обычно изобрели велосипед, вместо уже всем привычного JWT сделали…

👁 45410
Вот тут их мануал: core.telegram.org Получается так, у нас есть объект Telegram.WebApp в расширенном объекте window и выглядит он по этому интерфейсу:

interface WebAppData {
  initData: string;
  initDataUnsafe: {
    user: User;
    chat_instance: string;
    chat_type: string;
    auth_date: string;
    hash: string;
  };
  version: string;
  platform: string;
  colorScheme: string;
  themeParams: ThemeParams;
  isExpanded: boolean;
  viewportHeight: number;
  viewportStableHeight: number;
  isClosingConfirmationEnabled: boolean;
  isVerticalSwipesEnabled: boolean;
  headerColor: string;
  backgroundColor: string;
  BackButton: Button;
  MainButton: MainButton;
  SettingsButton: Button;
  HapticFeedback: Record<string, unknown>;
  CloudStorage: Record<string, unknown>;
  BiometricManager: BiometricManager;
}
Нас интересует строки: initData и hash. Где initData представляет собой URL-encoded строку query-параметров. И чтобы нам наладить работу между Ботом <-> Telegram Server <-> Backend, нам надо сделать эту коммуникацию безопасной, а значит нам надо как-то проверять, что запрос который пришел на backend, действительно от пользователя, а не от третьей стороны. Для этого мы должны использовать следующий алгоритм: 1. Декодировать строку initData, используя URL-encoding 2. Полученные пары ключ-значения сортируем в алфавитном порядке 3. Исключаем ключ hash 4. Из полученных пар составляем тело вида: auth_date=<auth_date>\nquery_id=<query_id>\nuser=<user> 5. Берем хэш от токена вашего бота с помощью алгоритма HMAC-SHA256, добавив дополнительный ключ 'WebAppData' 6. Берем хэш от полученного в шаге 4 тела с помощью того же алгоритма, а в качестве ключа используем хэш, полученный ранее в виде последовательности байтов (ВАЖНО! не hex-репрезентации!) 7. Сраниванием хэши. На самом деле не сложно, просто много текста, поэтому далее я написал подробно с комментами функцию валидации на JS:

function validateTelegramData(initData, botToken) {
  // Шаг 1: Декодируем строку
  const decodedData = querystring.parse(decodeURIComponent(initData));

  // Шаг 2: Получаем пары ключ-значение и сортируем их в алфавитном порядке
  const sortedKeys = Object.keys(decodedData).sort();

  // Шаг 3: Исключаем ключ 'hash'
  sortedKeys.splice(sortedKeys.indexOf('hash'), 1);

  // Шаг 4: Формируем строку для проверки
  const dataCheckString = sortedKeys
    .map(key => `${key}=${decodedData[key]}`)
    .join('\n');

  // Шаг 5: Берем хэш от токена вашего бота с помощью алгоритма HMAC-SHA256
  const secretKey = crypto.createHmac('sha256', 'WebAppData')
    .update(botToken)
    .digest();

  // Шаг 6: Берем хэш от полученного в шаге 4 тела с помощью того же алгоритма
  const calculatedHash = crypto.createHmac('sha256', secretKey)
    .update(dataCheckString)
    .digest('hex');

  // Шаг 7: Преобразуем полученный хэш в hex-строку и сравниваем со значением ключа 'hash'
  return calculatedHash === decodedData.hash;
}
Вот и все, далее по аналогии с JWT, если true, то данные валидны и значит это пользователь, если false, то данные скомпрометированы третьей стороной. Оставлю это здесь, ибо я запарился искать инфу как это сделать, надеюсь я вам сэкономлю кучу времени в будущем 👍 !💬Телеграм | !📹Youtube
📎 файл — готовится…
17