@mtNATS

Валидация пользователей WebAPP в Telegram, почему не работает?

Есть php скрипт, который 100% рабочий, пытаюсь при помощи него реализовать проверку данных пользователей WebAPP

получаю данные при помощи Telegram.WebApp.initData
user=%7B%22id%22%3A491735603%2C%22first_name%22%3A%22%F0%9F%85%BD%F0%9F%85%B0%EF%B8%8F%F0%9F%86%83%F0%9F%86%82%22%2C%22last_name%22%3A%22%22%2C%22username%22%3A%22mtNATS%22%2C%22language_code%22%3A%22ru%22%2C%22allows_write_to_pm%22%3Atrue%7D&chat_instance=-3312718360795391383&chat_type=sender&auth_date=1703053222&hash=05dd0f9552a0f12ea994e3616fccf18b0f4c151269664314d9dfd38202e431c5


пытаюсь отправить их при помощи js скрипта
const initDataString = Telegram.WebApp.initData;
    const serverURL = "/auth.php";

    function sendToServer(data) {
        const xhr = new XMLHttpRequest();
        xhr.open("GET", `${serverURL}?${data}`);
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    console.log("Server response:", xhr.responseText);
                } else {
                    console.error("Error:", xhr.status, xhr.statusText);
                }
            }
        };
        xhr.send();
    }
    sendToServer(initDataString);


function checkTelegramAuthorization($auth_data) {
    $check_hash = $auth_data['hash'];
    $_SESSION['hash'] = $check_hash;
    unset($auth_data['hash']);
    $data_check_arr = [];
    foreach ($auth_data as $key => $value) {
        $data_check_arr[] = $key . '=' . $value;
    }
    sort($data_check_arr);
    $data_check_string = implode("\n", $data_check_arr);
    $secret_key = hash('sha256', BOT_TOKEN, true);
    $hash = hash_hmac('sha256', $data_check_string, $secret_key);
    if (strcmp($hash, $check_hash) !== 0) {
        throw new Exception('Data is NOT from Telegram');
    }
    if ((time() - $auth_data['auth_date']) > 86400) {
        throw new Exception('Data is outdated');
    }
    return $auth_data;
}


в ответ получаю
Data is NOT from Telegram


помогите добиться результата! Спасибо!
  • Вопрос задан
  • 399 просмотров
Решения вопроса 1
IvanU7n
@IvanU7n
неправильно вычисляется secret_key, т.к. согласно документации он тоже должен быть чем-то вроде
hash_hmac('sha256', BOT_TOKEN, 'WebAppData', true);
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Хешер данных

class HasherDataAction
{
    const WEB_APP_DATA_CONST = 'WebAppData';

    public function handle(string $bot_token, ValidateData $data): string {
        $data_check = (array) $data;
        ksort($data_check, SORT_NATURAL);

        $data_check_string = urldecode(http_build_query($data_check, arg_separator: "\n"));

        $secret_key = $this->sha256($bot_token, self::WEB_APP_DATA_CONST);
        $hash_data = $this->sha256($data_check_string, $secret_key);

        return bin2hex($hash_data);
    }

    private function sha256(string $data, string $key) {
        return hash_hmac('sha256', $data, $key, true);
    }
}


ValidateData для передачи данных в метод хеширования

namespace WebApp\Domain\Data;

readonly class ValidateData
{
    public function __construct(
        public string $query_id,
        public string $user,
        public string $auth_date
    ) {
    }
}


JS

import axios from "axios";
const { initData } = window.Telegram.WebApp

document.addEventListener('DOMContentLoaded', () => {
  validateData(initData)
})

function validateData(data) {
  // как по мне лучше сразу передать данными и не парcить это в PHP, так проще и можно валидировать. 
  // axios.post('/{your_controller_validate_date}', data).then(response => {})
  
  // оставлю вариант с передачей строки в initData
  axios.post('/{your_controller_validate_date}', {initData: data})
    .then(response => {  console.log(response.data) })
}


// данные из JS, $_POST['initData']
$initData = 'user=%7B%22id%22%3A491735603%2C%22first_name%22%3A%22%F0%9F%85%BD%F0%9F%85%B0%EF%B8%8F%F0%9F%86%83%F0%9F%86%82%22%2C%22last_name%22%3A%22%22%2C%22username%22%3A%22mtNATS%22%2C%22language_code%22%3A%22ru%22%2C%22allows_write_to_pm%22%3Atrue%7D&chat_instance=-3312718360795391383&chat_type=sender&auth_date=1703053222&hash=05dd0f9552a0f12ea994e3616fccf18b0f4c151269664314d9dfd38202e431c5';

parse_str($initData, $data_array); // если отправляете данными, это не нужно, у вас сразу будет массив с данными в $_POST;

// $data_array = $_POST
$hash = $data_array['hash'];

$data = new ValidateData($data_array['query_id'], $data_array['user'], $data_array['auth_date']);
$data_hash = (new HasherDataAction)->handle('YOUR_BOT_TOKEN', $data);

// true/false
$isValid = $data_hash == $hash;
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы