Telegram

Проверка initData в Telegram Mini App на Python: код и ошибки

30 октября 2026 · 3 мин чтения

Кратко

initData из Mini App нужно проверять на сервере: секрет вычисляется как HMAC-SHA256 токена бота с ключом WebAppData, затем сравнивается подпись строки данных. Обязательны сравнение через compare_digest и проверка auth_date, чтобы отсечь подделку и старые данные.

Когда Mini App обращается к вашему серверу, вам нужно убедиться, что запрос действительно пришёл из Telegram от конкретного пользователя, а не от злоумышленника, который подставил чужой user_id. Для этого Telegram подписывает строку initData, а сервер проверяет подпись.

Как устроена проверка

Mini App получает Telegram.WebApp.initData — строку вида query_id=...&user=...&auth_date=...&hash=.... Проверка делается так:

  1. Разобрать строку на пары ключ-значение (значения декодируются из URL).
  2. Убрать поле hash, остальные пары отсортировать по ключу и склеить в строку ключ=значение, разделяя переводом строки.
  3. Вычислить секретный ключ: HMAC-SHA256, где ключ — строка WebAppData, а сообщение — токен бота.
  4. Вычислить HMAC-SHA256 строки из шага 2 с этим секретом и сравнить результат (в hex) с полученным hash.
  5. Проверить, что auth_date не старше разумного срока.

Рабочий код

import hashlib
import hmac
import json
import time
from urllib.parse import parse_qsl


def validate_init_data(init_data: str, bot_token: str, max_age: int = 3600) -> dict:
    """Возвращает данные Mini App, если подпись верна и данные свежие, иначе бросает ValueError."""
    pairs = dict(parse_qsl(init_data, keep_blank_values=True))
    received_hash = pairs.pop("hash", None)
    if not received_hash:
        raise ValueError("нет hash")

    check_string = "\n".join(f"{k}={v}" for k, v in sorted(pairs.items()))
    secret_key = hmac.new(b"WebAppData", bot_token.encode(), hashlib.sha256).digest()
    expected = hmac.new(secret_key, check_string.encode(), hashlib.sha256).hexdigest()

    if not hmac.compare_digest(expected, received_hash):
        raise ValueError("подпись не совпала")
    if time.time() - int(pairs.get("auth_date", 0)) > max_age:
        raise ValueError("данные устарели")

    if "user" in pairs:
        pairs["user"] = json.loads(pairs["user"])
    return pairs

Мы прогнали этот код на подписанном образце, на подмене данных, на чужом токене и на устаревшем auth_date: корректные данные принимаются, остальные отклоняются.

Как передать initData на сервер

Фронтенд отправляет строку в заголовке запроса, а сервер проверяет её на каждом обращении:

fetch("/api/me", { headers: { Authorization: "tma " + Telegram.WebApp.initData } });

Префикс tma — распространённая договорённость, а не требование Telegram. Пример проверки в aiohttp:

from aiohttp import web


async def me(request: web.Request) -> web.Response:
    auth = request.headers.get("Authorization", "")
    if not auth.startswith("tma "):
        raise web.HTTPUnauthorized()
    try:
        data = validate_init_data(auth[4:], BOT_TOKEN)
    except ValueError:
        raise web.HTTPUnauthorized()
    return web.json_response({"user_id": data["user"]["id"]})

В FastAPI та же функция подключается как зависимость (Depends), которая читает заголовок и вызывает validate_init_data.

Типичные ошибки

  • Проверка на клиенте. Подпись должна проверяться только на сервере: токен бота нельзя отдавать во фронтенд.
  • Сравнение через ==. Используйте hmac.compare_digest, чтобы не открыть атаку по времени ответа.
  • Забытый auth_date. Без проверки срока старые перехваченные данные работают вечно.
  • Неправильный порядок ключей или лишние поля в строке проверки. Поле hash в строку не входит, остальные идут отсортированными по алфавиту.
  • Не тот токен. Подпись привязана к токену конкретного бота. Если у вас несколько ботов, храните токен вместе с приложением.
  • Доверие к initDataUnsafe. Это те же данные без проверки. Использовать их для авторизации нельзя.

Где это пригодится

Проверка initData нужна любому Mini App, который хранит данные пользователя: избранное, подписки на уведомления, сохранённые поиски. Так устроены Mini App в наших проектах: Da Nang House и HotTrip. Если вы строите бота или Mini App, посмотрите услугу «Telegram-боты и Mini App».

Частые вопросы

Можно ли доверять user_id из initDataUnsafe?

Нет. `initDataUnsafe` — это распарсенные данные без проверки подписи. Для авторизации используйте только данные, которые прошли `validate_init_data`.

Как долго initData действителен?

Telegram передаёт время создания в `auth_date`, а срок годности определяете вы. Для обычных запросов хватает часа, для чувствительных операций берут меньше.

Что делать при ошибке «подпись не совпала»?

Проверьте, что токен принадлежит тому боту, из которого открыт Mini App, что `hash` исключён из строки проверки, что пары отсортированы по ключу и склеены переводом строки.

Нужна ли проверка, если Mini App только читает публичные данные?

Если данные публичны и не привязаны к пользователю, проверка не обязательна. Как только появляются личные данные или действия от имени пользователя, она обязательна.

Telegram Mini AppinitDataPythonбезопасностьHMAC

Версия для ИИ и чтения без оформления: Markdown.

Читайте также

Telegram · 30 октября 2026

Уведомления в Telegram Mini App: как слать пуши через бота

У Mini App нет собственных пушей: уведомления приходят как сообщения бота, а писать пользователю можно только после его запуска бота или запроса разрешения requestWriteAccess. Чтобы открыть нужный экран, используйте кнопку web_app или прямую ссылку с параметром startapp. Пользователей, заблокировавших бота, нужно отмечать и не беспокоить.

Telegram · 30 октября 2026

Telegram-бот на n8n: inline-кнопки, меню и кнопка для открытия Mini App

В n8n бот строится из Telegram Trigger, ветвления по типу события и узла отправки. Нажатия inline-кнопок приходят как callback_query и требуют ответа. Кнопку, открывающую Mini App, проще отправить через HTTP Request, а у бота может быть только один webhook.

Бизнес · 30 октября 2026

Сколько стоит Telegram-бот и Mini App: из чего складывается цена

Цена бота зависит от сценариев, интеграций и числа ролей, цена Mini App ещё и от интерфейса, API и данных. Простой бот стоит заметно меньше каталога с подписками. Экономия достигается запуском минимальной версии и ясным описанием задачи.

Расскажите о задаче

Опишите, что нужно сделать, даже в паре строк. Отвечу с вопросами или оценкой.

Обсудить проект →