You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在NestJS中正确验证Telegram Web App数据?

Telegram WebApp 数据验证哈希不匹配排查方案

优先排查代码问题(VPN影响哈希计算的概率极低)

  • 数据解析逻辑错误
    你的代码里用querystring.parse(authorizationData.telegramId),请确认authorizationData.telegramId是否是Telegram返回的原始query string格式字符串(比如auth_date=1690000000&hash=abcdef...&user={"id":123,...})。如果前端已经把initData解析成对象传给后端,再用querystring.parse会导致数据结构完全错误,最终哈希计算必然不匹配。建议先打印authorizationData.telegramId的实际值,确认格式是否正确。

  • 验证字符串换行符问题
    Telegram要求验证字符串的键值对用**LF换行符(\n)**分隔,确保你的join("\n")没有被转成CRLF(\r\n)。可以打印dataCheckString的原始内容,检查换行符是否正确。

  • 哈希大小写不统一
    Telegram返回的hash可能是十六进制小写或大写,而你的代码计算出的computedHash是小写(digest('hex')默认输出小写)。修改比较逻辑为统一大小写:

    if (computedHash.toLowerCase() !== hash.toLowerCase()) {
      console.log("Verification failed!");
    }
    
  • BotToken正确性
    确认configService获取到的TELEGRAM_BOT_TOKEN完全正确,没有多余的空格、引号或拼写错误。可以直接打印botToken的值和机器人后台的token对比。

  • 字段完整性检查
    确保data对象包含所有Telegram返回的字段(auth_date、user、chat_instance等,除了hash),且user字段是原始JSON字符串(未被前端解析成对象)。如果user被提前解析,拼接验证字符串时会变成user=[object Object],导致哈希计算错误。

VPN影响排查

VPN一般不会篡改HTTPS传输的数据,但可以做以下验证:

  1. 在前端打印Telegram.WebApp.initData的原始值,和后端收到的authorizationData.telegramId对比,确认内容完全一致,没有字段缺失或内容修改。
  2. 检查前端是否在传输过程中对initData做了额外编码/解码操作,导致数据变形。

修正后的代码示例(关键部分调整)

async authorizationTest(@Body() authorizationData: AuthorizeUserDto) {
    console.log("Body received from Telegram", authorizationData);

    const botToken = this.configService.get("TELEGRAM_BOT_TOKEN");
    // 先确认telegramId是原始query string,再解析
    const data = querystring.parse(authorizationData.telegramId);
    console.log("Data before hash", data);
    const hash = data.hash as string;
    delete data.hash;

    // 构建验证字符串,确保用LF换行
    const dataCheckString = Object.keys(data)
      .sort()
      .map((key) => `${key}=${data[key]}`)
      .join("\n");

    console.log("dataCheckString", dataCheckString);

    // 计算密钥
    const secretKey = crypto
      .createHmac("sha256", botToken)
      .update("WebAppData")
      .digest();

    // 计算哈希
    const computedHash = crypto
      .createHmac("sha256", secretKey)
      .update(dataCheckString)
      .digest("hex");

    console.log("computedHash", computedHash);
    // 统一大小写比较
    if (computedHash.toLowerCase() !== hash.toLowerCase()) {
      console.log("Verification failed!");
      return;
    }

    console.log("Hooray! Verification succeeded!");
    // 验证auth_date超时
    const CURRENT_UNIX_TIME = Math.floor(Date.now() / 1000);
    const TIMEOUT_SECONDS = 3600;
    if (CURRENT_UNIX_TIME - Number(data.auth_date) > TIMEOUT_SECONDS) {
      console.log("Verification failed due to timeout");
      return;
    }

    console.log("Verification successful");
}

内容的提问来源于stack exchange,提问作者tron21

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 18:28:34