Legan Studio
Все статьи
~ 6 мин чтения

Telegram Passport: проверка документов в боте

Как принимать документы через Telegram Passport: настройка публичного ключа, расшифровка credentials, проверка хешей и сценарии KYC для боту.

  • Telegram
  • Passport
  • KYC
  • безопасность

Telegram Passport — это сервис идентификации пользователя через Telegram: юзер один раз загружает скан паспорта, водительского удостоверения, ИНН или адресного документа в защищённое хранилище Telegram, и потом может отдать эти данные вашему боту в один клик. Для бизнеса это инструмент KYC (Know Your Customer) без ручной проверки документов.

Разберём, как настроить публичный ключ для бота, как обрабатывать passport_data, как расшифровать данные с серверной стороны и какие сценарии реально работают.

Что такое Telegram Passport

Юзер хранит зашифрованные документы (паспорт, права, ИНН, адрес) в Telegram. Когда сервис запрашивает их, юзер подтверждает в один тап, и Telegram передаёт данные только этому сервису, расшифровать их может только владелец приватного RSA-ключа.

Это уже не просто хеш «есть документ / нет», а полные данные: ФИО, дата рождения, серия-номер, скан, селфи. Для KYC по 115-ФЗ или верификации перед сделкой это огромная экономия времени.

Когда применяется

Хорошие сценарии:

  • Криптообменники, P2P-биржи (юридически обязаны KYC).
  • Сервисы аренды (авто, недвижимость) — проверка прав и паспорта.
  • Финтех-боты — выдача займов, кредитные карты.
  • Образовательные платформы с дипломами от имени юзера.
  • Ставки/букмекеры — возрастная верификация.

Плохие сценарии:

  • Обычные интернет-магазины — overkill, юзеры не дают документы.
  • Подписки на контент — отпугивает аудиторию.
  • B2C-сервисы без юридической необходимости.

Настройка ключа

Telegram Passport использует RSA-2048. Сгенерируйте пару ключей:

openssl genrsa -out passport_private.key 2048
openssl rsa -in passport_private.key -pubout -out passport_public.key

Публичный ключ — в @BotFather/setpublickey → выбираете бота → вставляете passport_public.key. Приватный — на бэкенде, в защищённом хранилище (KMS, Vault, encrypted env).

Запрос данных

В клиенте используется виджет Telegram Passport через passport://request. Параметры зашифрованы и подписаны через nonce:

const params = new URLSearchParams({
  bot_id: "1234567890",
  scope: JSON.stringify({
    data: [
      { type: "passport", selfie: true },
      { type: "address" },
      { type: "phone_number" },
      { type: "email" },
    ],
    v: 1,
  }),
  public_key: PUBLIC_KEY_PEM,
  nonce: crypto.randomUUID(),
  callback_url: "https://api.example.com/passport/callback",
}).toString();

const url = `tg://resolve?domain=telegrampassport&${params}`;
// открыть из Mini App или дать ссылкой

Юзер открывает Telegram, выбирает данные, подтверждает биометрией → Telegram отправляет на ваш callback_url либо в апдейт passport_data в боте.

Обработка passport_data в боте

from aiogram import Router, F
from aiogram.types import Message

router = Router()

@router.message(F.passport_data)
async def passport(message: Message):
    pd = message.passport_data
    # pd.data — список EncryptedPassportElement
    # pd.credentials — EncryptedCredentials с зашифрованным ключом
    decoded = decrypt_passport(pd, PRIVATE_KEY)
    await users.save_kyc(message.from_user.id, decoded)
    await message.answer("Документы получены. Проверка займёт до 5 минут.")

Все поля приходят зашифрованными AES-256-CBC, ключ зашифрован вашим RSA-публичным.

Расшифровка

Высокоуровневый алгоритм:

  1. Расшифровать credentials.secret приватным RSA-ключом (OAEP).
  2. Получить secret, data_hash.
  3. Из secret и data_hash вывести AES-ключ и IV (SHA-512).
  4. Расшифровать data AES-256-CBC.
  5. Проверить, что SHA-256 от расшифрованных данных совпадает с data_hash.

В Python готовая библиотека — aiogram-passport или ручная реализация на cryptography:

from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
import hashlib, base64, json

def decrypt_credentials(enc_credentials, private_key):
    secret = base64.b64decode(enc_credentials.secret)
    decrypted_secret = private_key.decrypt(
        secret,
        padding.OAEP(
            mgf=padding.MGF1(algorithm=hashes.SHA512()),
            algorithm=hashes.SHA512(),
            label=None,
        ),
    )
    data = base64.b64decode(enc_credentials.data)
    hash_ = base64.b64decode(enc_credentials.hash)
    key, iv = derive_key_iv(decrypted_secret, hash_)
    plaintext = aes_cbc_decrypt(data, key, iv)
    if hashlib.sha256(plaintext).digest() != hash_:
        raise ValueError("hash mismatch — данные подделаны")
    return json.loads(strip_padding(plaintext))

derive_key_iv берёт SHA-512 от secret + hash и режет на 32 байта ключа и 16 байт IV.

Что приходит внутри

ТипПоля
personal_detailsfirst_name, last_name, middle_name, birth_date, gender, country_code, residence_country, citizenship
passportdocument_no, expiry_date, issued_date + сканы front_side, selfie
internal_passportномер, скан
driver_licenseномер, селфи, скан
addressstreet_line1, city, state, country_code, post_code
utility_billсканы для подтверждения адреса
phone_numberстрока
emailстрока

Сканы приходят как PassportFile с file_id — скачиваются через getFile и тут же расшифровываются тем же ключом.

Юридические аспекты

В РФ Telegram Passport не аккредитован как УЦ, поэтому юридически это не электронная подпись и не заменяет нотариальную заверку. Это удобный канал доставки документов, дальше вам нужно самим проверять их на подлинность.

По 152-ФЗ хранение скана паспорта — обработка специальной категории ПД, требующая отдельного согласия. В оферте бота должно быть явное указание, какие данные собираются, зачем, на какой срок.

Альтернативы

  • СберID / Тинькофф ID — для российских банковских юзеров, юридически сильнее.
  • Госуслуги ЕСИА — самый сильный юридически, но требует интеграции через лицензированный сервис.
  • Ручная загрузка фото в боте — без шифрования, но без зависимости от Passport.

Telegram Passport — это лёгкий middle-ground между «загрузите PDF» и «авторизация через ЕСИА».

Топ-5 ошибок

  1. Хранят приватный RSA-ключ в репозитории — компрометация = доступ ко всем переданным документам.
  2. Не сравнивают SHA-256 после расшифровки — пропускают подделанные данные.
  3. Складывают сканы в S3 без шифрования — нарушение 152-ФЗ.
  4. Не выкатывают cookie-баннер и согласие на обработку ПД до запроса Passport.
  5. Используют Telegram Passport вместо настоящего KYC и потом не могут пройти регуляторную проверку.

Итого

Telegram Passport — мощный инструмент для KYC внутри Telegram-сервиса: юзер один раз загрузил документы, и любой бот может их получить с его согласия. Технически нужно RSA-ключ, серверная расшифровка и грамотное хранение. Юридически — это не подпись, а канал доставки документов, реальная проверка остаётся на вас. Подходит для финтеха, аренды, ставок, сервисов с обязательной верификацией возраста.

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

Поддерживает ли Telegram Passport биометрическое подтверждение?

Да, при отправке данных юзер подтверждает действие Touch ID / Face ID или паролем Telegram. Это даёт дополнительный фактор и фиксирует намерение. На бэкенд приходит лишь факт успешной отправки — самих биометрических данных вы не видите, и хорошо: их хранение требует отдельной лицензии.

Можно ли запросить только одно поле, например только email?

Да, в scope указываете только нужные типы. Юзер увидит компактный диалог только с этими полями. Это полезно для лёгких сценариев: подтверждение email и телефона без скана паспорта — нагрузка на юзера минимальная, согласие быстрое.

Как часто можно запрашивать данные?

Лимитов от Telegram нет, но юзер видит, какому боту он что отдавал, и может отозвать доступ в любой момент. Хорошее правило — запрашивать один раз и сохранять расшифрованные данные у себя на бэкенде, шифруя на стороне приложения. Повторный запрос делайте только после изменения требований (например, появилось требование подтвердить адрес).

Что делать, если расшифровка не проходит проверку хеша?

Не доверяйте таким данным — это либо технический сбой, либо попытка подделки. Логируйте инцидент с update_id, user_id, отказывайте в KYC, можете предложить юзеру повторить отправку. Никогда не сохраняйте «полурасшифрованные» данные в продакшен-БД.

Можно ли проверить, что скан настоящий, а не нарисованный?

Telegram Passport не делает liveness-проверку и не верифицирует подлинность документа. Это просто канал передачи. Для серьёзного KYC подключайте сторонние сервисы (Sumsub, Veriff, IDX) — они проверяют MRZ, сравнивают селфи с фото в документе и дают вердикт «pass/fail».

Сколько хранятся данные на стороне Telegram?

Telegram хранит зашифрованные документы юзера до тех пор, пока юзер сам их не удалит. Доступ к ним получает только тот сервис, кому юзер явно их отдал. Сам Telegram расшифровать данные не может — у него нет ключа.

Можно ли использовать Passport в Mini App, а не в боте?

Да, через passport:// URL-схему или Telegram.WebApp.openLink с правильно сформированным запросом. Логика та же: вы передаёте bot_id, public_key, scope, nonce, callback_url. Юзер видит тот же экран Telegram Passport, и данные приходят на ваш callback или в бот.