C#实现Telegram登录时HMAC哈希校验结果不匹配问题
Telegram登录组件哈希校验不匹配解决方案
核心问题原因
你的代码存在两个致命逻辑错误,同时你使用的第三方NuGet包本身存在已知兼容bug,都会导致哈希计算结果和Telegram返回值不一致:
- 校验字符串拼接逻辑错误:你硬编码了字段顺序,还手动给最后一个字段省略换行符。按照官方规则,需要排除
hash字段后,将剩余所有字段按字段名的字典序升序排列,相邻key=value对之间用\n分隔,硬编码顺序、手动处理换行的写法在字段缺失、新增时会直接生成错误的拼接串。 - 第三方包过时失效:你用的
Telegram.Bot.Extensions.LoginWidget包早已停止维护,内部字段排序、编码逻辑存在bug,无法兼容Telegram后续新增的返回字段,不建议使用。 - 额外容易踩的坑:如果对Telegram返回的字段值做了URL解码、转义、类型转换再拼接,也会导致哈希不匹配,必须使用原始返回值。
正确实现代码
using System.Security.Cryptography; using System.Text; public static bool VerifyTelegramAuth(IReadOnlyDictionary<string, string> authParams, string botToken) { // 取出Telegram返回的哈希值 if (!authParams.TryGetValue("hash", out string? telegramHash)) return false; // 按规则拼接校验串:排除hash字段、按字段名字典序升序、\n分隔键值对 var checkString = string.Join('\n', authParams .Where(kv => kv.Key != "hash") .OrderBy(kv => kv.Key, StringComparer.Ordinal) .Select(kv => $"{kv.Key}={kv.Value}")); // 计算密钥:BotToken的SHA256值 byte[] secretKey; using (var sha256 = SHA256.Create()) { secretKey = sha256.ComputeHash(Encoding.UTF8.GetBytes(botToken)); } // 计算HMAC-SHA256 byte[] hashBytes; using (var hmac = new HMACSHA256(secretKey)) { hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(checkString)); } // 转小写十六进制对比 var computedHash = Convert.ToHexString(hashBytes).ToLowerInvariant(); var isHashValid = computedHash == telegramHash.ToLowerInvariant(); // 额外校验:auth_date超过24小时直接判定无效,防重放攻击 if (isHashValid && authParams.TryGetValue("auth_date", out string? authDateStr) && long.TryParse(authDateStr, out long authDate)) { var expireTime = DateTimeOffset.FromUnixTimeSeconds(authDate).AddHours(24); return expireTime > DateTimeOffset.UtcNow; } return isHashValid; }
测试注意事项
- 不要用自己构造的模拟数据测试,必须用Telegram登录组件实际回调返回的完整原始参数测试
- 所有参数值必须使用Telegram返回的原始字符串,不要做任何URL解码、HTML转义、格式转换
- 如果你的站点是HTTPS,确保在Bot Father里设置的回调域和实际访问域名完全一致,否则返回的参数本身就是非法的
内容的提问来源于stack exchange,提问作者vuradzu
相关产品推荐
相关产品推荐

