PHP中Telegram小程序数据验证失败问题排查
问题
在PHP中实现Telegram小程序数据验证函数时,验证始终返回false。使用相同的bot token,传入指定参数调用validate_telegram_data时,计算出的哈希值与接收的哈希值不一致:
- 接收哈希:
1540cf7e36ebbadfe7faea9f20ccc68431cb24e1d106f860d27a560309f1ca3b - 计算哈希:
493b5e631f8aae6061e9079b961506c07f61a3fb4b31810ad26b01b9b1cfaadb
实现代码:
function hmac_sha256($key, $data) { return hash_hmac('sha256', $data, $key, true); } function validate_telegram_data($received_data) { global $bot_token; parse_str($received_data, $data); ksort($data); $received_hash = $data['hash']; unset($data['hash']); $data_check_string = ''; foreach ($data as $key => $value) { $data_check_string .= $key . '=' . $value . "\n"; } // print_r($data_check_string); $secret_key = hmac_sha256($bot_token, "WebAppData"); $computed_hash = bin2hex(hmac_sha256($secret_key, $data_check_string)); // print_r([$received_hash, $computed_hash]); if (hash_equals($computed_hash, $received_hash)) { if (isset($data['auth_date']) && (time() - intval($data['auth_date'])) < 86400) { return true; } } return false; }
调用代码:
validate_telegram_data('query_id=AAGohX8eAwAAAKiFfx7ierlk&user=%7B%22id%22%3A6954124712%2C%22first_name%22%3A%22Socilizer%20Support%22%2C%22last_name%22%3A%22%22%2C%22username%22%3A%22socilizer_support%22%2C%22language_code%22%3A%22en%22%2C%22allows_write_to_pm%22%3Atrue%7D&auth_date=1725191023&hash=1540cf7e36ebbadfe7faea9f20ccc68431cb24e1d106f860d27a560309f1ca3b'); // 返回false,原因?
问题排查与修复
核心问题点
HTML转义字符污染代码
你提供的代码中存在大量HTML转义字符(如=>、"、&&、<),这些字符会被PHP解析为字符串的一部分,而非正确的语法符号或字符串内容:$key => $value会被解析为错误的赋值语句,而非foreach循环的键值对语法"WebAppData"会被当成带双引号的字符串"WebAppData",而Telegram要求的是不带引号的WebAppData
换行符格式错误
Telegram要求拼接data_check_string时,每个键值对后必须添加单个换行符(\n),而你代码中使用的是实际换行(而非转义字符\n),在不同操作系统下可能会生成\r\n(Windows),导致哈希计算不匹配。
修正后的代码
function hmac_sha256($key, $data) { return hash_hmac('sha256', $data, $key, true); } function validate_telegram_data($received_data) { global $bot_token; // 解析URL参数,提前判断哈希是否存在 parse_str($received_data, $data); if (!isset($data['hash'])) { return false; } // 按字典序排序参数 ksort($data); $received_hash = $data['hash']; unset($data['hash']); // 生成符合Telegram要求的校验字符串 $data_check_string = ''; foreach ($data as $key => $value) { $data_check_string .= "{$key}={$value}\n"; } // 生成Telegram指定的密钥 $secret_key = hmac_sha256($bot_token, "WebAppData"); // 计算并转换为十六进制哈希 $computed_hash = bin2hex(hmac_sha256($secret_key, $data_check_string)); // 安全比较哈希,同时校验数据有效期 if (hash_equals($computed_hash, $received_hash)) { if (isset($data['auth_date']) && (time() - intval($data['auth_date'])) < 86400) { return true; } } return false; }
额外注意事项
- 确保
$bot_token变量已正确定义,且与Telegram Bot的Token完全一致(无多余空格或符号) parse_str会自动解码URL编码的参数,无需额外处理user字段- 使用
hash_equals而非普通字符串比较,避免时序攻击
内容的提问来源于stack exchange,提问作者KAATIL SUKRAT
相关产品推荐
相关产品推荐

