如何验证通过 Telegram 的 Web 应用程序收到的数据

问题描述 投票:0回答:4

我正在尝试验证 WebApp 数据,但结果不是我想要的。

电报文档

data_check_string = ...
secret_key = HMAC_SHA256(<bot_token>, "WebAppData")
if (hex(HMAC_SHA256(data_check_string, secret_key)) == hash) {
    // data is from Telegram
}

我的代码:

BOT_TOKEN = '5139539316:AAGVhDje2A3mB9yA_7l8-TV8xikC7KcudNk'

data_check_string = 'query_id=AAGcqlFKAAAAAJyqUUp6-Y62&user=%7B%22id%22%3A1246866076%2C%22first_name%22%3A%22Dante%22%2C%22last_name%22%3A%22%22%2C%22username%22%3A%22S_User%22%2C%22language_code%22%3A%22en%22%7D&auth_date=1651689536&hash=de7f6b26aadbd667a36d76d91969ecf6ffec70ffaa40b3e98d20555e2406bfbb'
data_check_arr = data_check_string.split('&')
needle = 'hash='
hash_item = ''
telegram_hash = ''
for item in data_check_arr:
    if item[0:len(needle)] == needle:
        telegram_hash = item[len(needle):]
        hash_item = item
data_check_arr.remove(hash_item)
data_check_arr.sort()
data_check_string = "\n".join(data_check_arr)
secret_key = hmac.new("WebAppData".encode(), BOT_TOKEN.encode(),  hashlib.sha256).digest()
calculated_hash = hmac.new(data_check_string.encode(), secret_key, hashlib.sha256).hexdigest()

print(calculated_hash == telegram_hash) # print False

我正在尝试在 python 中验证 webapp 数据,但我的代码没有给出预期的结果。 我的代码给我的哈希值与电报的哈希值不同。

更新:添加了有效数据,并且机器人令牌已更改。

python encryption hash telegram telegram-bot
4个回答
3
投票

您可以用几行替换 for 循环(已经合并了 kurdyukovpv 的建议以取消引用查询字符串):

data_check_string = sorted([ chunk.split("=") for chunk in unquote(data_check_string).split("&") 
        if chunk[:len("hash=")]!="hash="],
        key=lambda x: x[0])
data_check_string = "\n".join([f"{rec[0]}={rec[1]}" for rec in data_check_string])

编辑:我想我也可以发布我从这个线程中得到的整个工作函数):

import hmac
import hashlib
from urllib.parse import unquote

def validate(hash_str, init_data, token, c_str="WebAppData"):
    """
    Validates the data received from the Telegram web app, using the
    method documented here: 
    https://core.telegram.org/bots/webapps#validating-data-received-via-the-web-app

    hash_str - the has string passed by the webapp
    init_data - the query string passed by the webapp
    token - Telegram bot's token
    c_str - constant string (default = "WebAppData")
    """

    init_data = sorted([ chunk.split("=") 
          for chunk in unquote(init_data).split("&") 
            if chunk[:len("hash=")]!="hash="],
        key=lambda x: x[0])
    init_data = "\n".join([f"{rec[0]}={rec[1]}" for rec in init_data])

    secret_key = hmac.new(c_str.encode(), token.encode(),
        hashlib.sha256 ).digest()
    data_check = hmac.new( secret_key, init_data.encode(),
        hashlib.sha256)

    return data_check.hexdigest() == hash_str

1
投票

您需要取消引用 data_check_string

from urllib.parse import unquote 
data_check_string = unquote('query_id=AAGcqlFKAAAAAJyqUUp6-Y62&user=%7B%22id%22%3A1246866076%2C%22first_name%22%3A%22Dante%22%2C%22last_name%22%3A%22%22%2C%22username%22%3A%22S_User%22%2C%22language_code%22%3A%22en%22%7D&auth_date=1651689536&hash=de7f6b26aadbd667a36d76d91969ecf6ffec70ffaa40b3e98d20555e2406bfbb')

并交换参数

calculated_hash = hmac.new(secret_key, data_check_string.encode(), hashlib.sha256).hexdigest()

0
投票
import hmac
import hashlib
from urllib.parse import unquote

def validate(hash_str, init_data, token, c_str="WebAppData"):
    """
    Validates the data received from the Telegram web app, using the
    method documented here: 
    https://core.telegram.org/bots/webapps#validating-data-received-via-the-web-app

    hash_str - the has string passed by the webapp
    init_data - the query string passed by the webapp
    token - Telegram bot's token
    c_str - constant string (default = "WebAppData")
    """

    init_data = sorted([ chunk.split("=") 
          for chunk in unquote(init_data).split("&") 
            if chunk[:len("hash=")]!="hash="],
        key=lambda x: x[0])
    init_data = "\n".join([f"{rec[0]}={rec[1]}" for rec in init_data])

    secret_key = hmac.new(c_str.encode(), token.encode(),
        hashlib.sha256 ).digest()
    data_check = hmac.new( secret_key, init_data.encode(),
        hashlib.sha256)

    return data_check.hexdigest() == hash_str


it is working BUT there is a problem when first_name contains &

RESOLIVNG IS

init_data = sorted([chunk.split("=") for chunk in init_data.split("&") if chunk[:len("hash=")] != "hash="], key=lambda x: x[0])
    init_data = "\n".join([f"{rec[0]}={unquote(rec[1])}" for rec in init_data])
    secret_key = hmac.new(c_str.encode(), token.encode(), hashlib.sha256).digest()
    data_check = hmac.new(secret_key, init_data.encode(), hashlib.sha256)
    return data_check.hexdigest() == hash_str

do {unquote(rec[1]) after sorting`enter code here`

0
投票

我重构了之前答案的代码:

  • 该函数从给定的 initData 中获取哈希值

  • unquote
    是用
    &
    拆分后的唯一值,以解决如何验证通过 Telegram 的 Web 应用程序接收到的数据

    中所述的问题
  • 更多Python风格

     def validate_init_data(init_data: str, bot_token: str):
         vals = {k: unquote(v) for k, v in [s.split('=', 1) for s in init_data.split('&')]}
         data_check_string = '\n'.join(f"{k}={v}" for k, v in sorted(vals.items()) if k != 'hash')
    
         secret_key = hmac.new("WebAppData".encode(), bot_token.encode(), hashlib.sha256).digest()
         h = hmac.new(secret_key, data_check_string.encode(), hashlib.sha256)
         return h.hexdigest() == vals['hash']
    

感谢之前的答案的见解!

© www.soinside.com 2019 - 2024. All rights reserved.