@@ 0,0 1,128 @@
+---
+title: "Telegram Web App bot: как безопасно общаться такому боту с мессенджером"
+date: 2022-06-14T15:01:43+03:00
+layout: post
+---
+
+С релизом нового обновления Telegram у многих возникли вопросы как правильно наладить общение `бот <-> Telegram`
+и сделать это безопасно. Для начала давайте проясним какие способы активации Telegram решил предоставить пользователю:
+1. Через кнопку меню, которую можно настроить у `@BotFather`.
+2. Через inline-кнопку.
+3. Через keyboard-кнопку.
+4. Через меню вложений.
+
+
+
+Первый и второй способ предлагают нам аутентифицировать и авторизовать пользователя через специальный объект `initData`,
+который можно достать с помощью JavaScript. Объект имеет следующую структуру:
+```json
+{
+ "query_id": "str",
+ "user": {
+ "id": 1,
+ "is_bot": false,
+ "first_name": "Pavel",
+ "last_name": "Durov",
+ "username": "durov",
+ "language_code": "ru",
+ "photo_url": "https://telegram.org/durov.jpg"
+ },
+ "auth_date": 1655210062,
+ "hash": "7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069"
+}
+```
+
+Проблема в том, что официальная документация хоть и предупреждает, но не особо объясняет зачем валидировать
+поле `initData` на сервере бота.
+
+**TL;DR**
+
+Без валидации:
+> **Мэллори:** Привет Боб, я Алиса, дай мне информацию о балансе и сделай перевод на имя Мэллори.
+>
+> **Боб:** Пожалуйста, Алиса, всё готово.
+
+С валидацией:
+> **Мэллори:** Привет Боб, я Алиса, дай мне информацию о балансе и сделай перевод на имя Мэллори.
+>
+> **Боб:** Предоставьте, пожалуйста, валидную подпись Алисы.
+>
+> _Мэллори разводит руками_
+
+То есть нужно это затем, чтобы произвести безопасную аутентификацию (проверку подлинности запроса) и авторизацию
+(понять, что к боту пришла именно Алиса, а не Мэллори).
+
+Без этой валидации бот сможет предоставлять критически важную информацию (например, вы делаете онлайн-банкинг в боте)
+просто по ID пользователя Telegram.
+
+Важно также понимать, что валидация должна происходить **исключительно** на серверной части.
+Валидация на клиентской части мало того, что бессмысленна, так ещё и скомпрометирует токен вашего бота.
+
+Валидация, к слову, не совсем тривиальная. Разработчики Telegram, как обычно, не поленились и вместо проверенного
+стандарта JSON Web Token (JWT), реализовали свой собственный велосипед, да ещё и на базе обычного HMAC-SHA256
+(то есть HS256 будь у нас JWT-токен). В результате `initData` представляет собой URL-encoded
+строку query-параметров. Для корректной валидации которой требуется следующая цепочка шагов:
+
+1. Декодируем строку, используя URL-encoding (важно, иначе значение с ключом `user` останется не декодированным).
+2. Полученные пары ключ-значения сортируем в алфавитном порядке.
+3. Исключаем ключ `hash`
+4. Из полученных пар составляем тело вида: `auth_date=<auth_date>\nquery_id=<query_id>\nuser=<user>`. Важно сохранить значение с ключом `user` в чистом JSON.
+5. Берем хэш от токена вашего бота с помощью алгоритма HMAC-SHA256 с ключом `WebAppData`.
+6. Берем хэш от полученного в шаге 4 тела с помощью того же алгоритма, а в качестве ключа используем хэш, полученный ранее в виде последовательности **байтов** (а не hex-репрезентации!).
+7. Преобразуем полученный хэш в hex-строку и сравниваем со значением ключа `hash`.
+
+По аналогии с JWT, если валидация прошла успешно, пользователя можно считать аутентифицированным
+и переходить к авторизации с помощью предоставленного payload (в нашем случае это `id` в объекте `user`).
+
+Говоря о `query_id`, который мы получаем в `initData`. Используя это поле, мы можем создать в чате сообщение с ботом
+от имени пользователя с бейджем `via @your_bot`. Для этого потребуется вызвать метод [answerWebAppQuery](https://core.telegram.org/bots/api#answerwebappquery).
+
+
+
+<div class="alert alert-success">
++ может использоваться для приложений любой сложности<br/>
++ <code>initData</code> по факту является полноценным stateless-токеном по типу JWT<br/>
++ позволяет создавать сообщения от имени пользователя в чате с ботом с бейджем <code>via @your_bot</code><br/>
+</div>
+<div class="alert alert-error">
+- требуется собственный бэкенд для веб-части для валидации <code>initData</code> и работы с пользователем
+</div>
+
+Вернёмся к способам активации. С первым и вторым способом всё понятно: вы получаете от Telegram подобие готового токена
+и поэтому реализация собственной аутентификации и авторизации не требуется, требуется только валидация.
+
+Но с третьим способом ситуация с одной стороны проще, с другой сложней. Дело в том, что `initData` не приходит
+и наладить общение с серверной частью не выйдет. Ведь вы не будете знать кто к вам пришёл.
+
+Однако при использовании этого способа появляется возможность использовать метод `Telegram.WebApp.sendData()`,
+который позволяет отправить сообщение боту напрямую, а тот предоставит его вам через long-polling или вебхуки.
+Стоит учесть, что после успешного выполнения веб-окно автоматически закроется, а бот отрапортует сервисным сообщением
+`Вы успешно передали данные боту кнопкой «Test button».`
+
+Поэтому Telegram позиционирует этот способ как удобный способ сделать гибкую веб-форму ввода с полями
+типа `date picker`. Вернуть значения формы можно с помощью метода `Telegram.WebApp.sendData()`.
+
+Нужно понимать, что в JS-файле этот метод является лишь прослойкой,
+само значение, переданное в `sendData()` отправляются далее через
+[MTProto-метод](https://github.com/tdlib/td/blob/047246f366d94b55ea7b6b93b3a4baa9a3380154/td/generate/scheme/td_api.tl#L4968)
+`sendWebAppData`. Методы MTProto невозможно использовать без авторизации в Telegram, поэтому тут мессенджер берет
+безопасность полностью на себя.
+
+В этом заключается плюс этого метода.
+
+<div class="alert alert-success">
++ удобно для заполнения сравнительно простых форм ввода<br/>
++ наличие собственного бэкенда для Web-части не требуется<br/>
+</div>
+<div class="alert alert-error">
+- <code>initData</code> не приходит, возможность авторизовать пользователя на своём бэкенде (даже если он есть) отсутствует<br/>
+- отправить информацию боту можно только 1 раз
+</div>
+
+Есть также четвертый способ, который технически не отличается от первого и второго
+(только дополнительными полями в `initData`), но в этом случае бот добавляется
+в меню вложений.
+
+К сожалению эта возможность пока что доступна только для тех, кто участвует в рекламной платформе Telegram
+и, следовательно, внёс залог 2 миллиона евро. Поэтому пока что говорить тут особо не о чем.
+Из известных мне публичных ботов такую интеграцию использует [@wallet](https://t.me/wallet).<
\ No newline at end of file