Почему не работает валидация токена для виджета входа через Telegram?

У меня есть код для бэкенда, который валидирует хэш, полученный от Telegram. Я отправляю запрос на бэкенд с корректными данными, но хэш не совпадает. Вот мой код: 

```python
def sha256(key):
    return hashlib.sha256(key.encode('utf-8')).digest()

def hmac_sha256(data, secret_key):
    return hmac.new(secret_key, data.encode('utf-8'), hashlib.sha256).hexdigest()

def verify_telegram_data(bot_token, received_hash, **kwargs):
    sorted_keys = sorted(kwargs.keys())
    data_check_string = "\n".join(f"{key}={kwargs[key]}" for key in sorted_keys)
    print(data_check_string)
    secret_key = sha256(bot_token)

    calculated_hash = hmac_sha256(data_check_string, secret_key)

    print(calculated_hash)

    return calculated_hash == received_hash
```

```python
async def create_session(request: Request):
    body = await request.json()
    print(body)
    try:
        hash = str(body['hash'])
        auth_date = int(body['auth_date'])
        first_name = str(body['first_name'])
        id = str(body['id'])
        username = str(body['username'])

    except: 
        return 'BAD PARAMS'

    return verify_telegram_data(
        config.TOKEN,
        hash,
        auth_date=auth_date,
        first_name=first_name,
        id=id,
        username=username
    )
```

Вот тело запроса, который я отправляю на сервер (данные изменены для безопасности):

```json
{
    "hash": "хэш",
    "auth_date": "дата",
    "first_name": "имя",
    "id": "ид",
    "username": "юзер"
}
```

Что может быть причиной несовпадения хэша?
  • 18 октября 2024 г. 18:32
Ответы на вопрос 2
Некоторые распространенные причины, по которым может происходить несовпадение при валидации хэша для входа через Telegram, включают:

### 1. Неправильный формат данных
Убедитесь, что передаваемые данные в `kwargs` имеют правильные названия и типы. Telegram отправляет значения в определенном формате, и любое несовпадение, например, лишние пробелы или неправильное деление по типам (например, строка вместо целого числа), может привести к ошибке.

### 2. Как формируется строка для хэширования
Убедитесь, что строка, используемая для формирования хэша (`data_check_string`), составлена правильно. Она должна быть отсортирована по ключам в лексикографическом порядке и содержать только ключи без значений. Правильно сформированная строка должна выглядеть как:

```
auth_date=<auth_date>
first_name=<first_name>
id=<id>
username=<username>
```

Каждая строка должна быть добавлена на новой строке.

### 3. Использование правильного секретного ключа
Убедитесь, что вы используете правильный токен бота и правильно его хэшируете для получения `secret_key`. 

### 4. Хэширование
Убедитесь, что в функции `hmac_sha256` вы корректно используете `secret_key`. Она должна быть побитовой (binary) строкой при создании HMAC.

Попробуйте использовать следующий корректированный код:

```python
import hashlib
import hmac

def sha256(key):
    return hashlib.sha256(key.encode('utf-8')).digest()

def hmac_sha256(data, secret_key):
    return hmac.new(secret_key, data.encode('utf-8'), hashlib.sha256).hexdigest()

def verify_telegram_data(bot_token, received_hash, **kwargs):
    sorted_keys = sorted(kwargs.keys())
    data_check_string = "\n".join(f"{key}={kwargs[key]}" for key in sorted_keys)
    print("Data check string:", data_check_string)
    
    secret_key = sha256(bot_token)

    calculated_hash = hmac_sha256(data_check_string, secret_key)

    print("Calculated hash:", calculated_hash)

    return calculated_hash == received_hash

async def create_session(request: Request):
    body = await request.json()
    print("Received body:", body)

    try:
        hash = str(body['hash'])
        auth_date = str(body['auth_date'])  # Обратите внимание на строковый тип
        first_name = str(body['first_name'])
        id = str(body['id'])
        username = str(body['username'])

    except KeyError: 
        return 'BAD PARAMS'

    return verify_telegram_data(
        config.TOKEN,
        hash,
        auth_date=auth_date,
        first_name=first_name,
        id=id,
        username=username
    )
```

### 5. Пробелы и другие неожиданные символы
Убедитесь, что в полученных значениях нет лишних пробелов или символов. Это можно сделать, применив метод `strip()`:

```python
auth_date = str(body['auth_date']).strip()
first_name = str(body['first_name']).strip()
id = str(body['id']).strip()
username = str(body['username']).strip()
```

### 6. Проверьте токен бота
Проверьте, что токен бота (`config.TOKEN`) скопирован и используется без ошибок (например, пробелов или отсутствующих символов).

Проверив все вышеперечисленные моменты, вы сможете выявить причину несовпадения хэша.
Похожие вопросы