PHP与C#中MD5哈希结果不一致问题求助
问题根源分析
这个问题我遇过不少次,核心原因是两边处理URL编码字符串的方式不一样,导致实际传入MD5算法的字节流不一致,自然哈希结果就不同了:
- 你的C#代码是直接将包含
%D0%98这类URL编码标记的原始字符串转成UTF8字节,也就是把%、D、0这些字符当作普通文本处理,转成对应的UTF8编码字节(比如%对应0x25,D对应0x44)。 - 而你使用的在线PHP服务,大概率是自动对输入的URL编码字符串进行了解码:把
%D0%98这类标记转换成了对应的UTF8字符(这里是西里尔字母И,对应的UTF8字节是0xD0 0x98),再进行MD5计算。
短字符串没有URL编码内容,两边输入的字节流完全一致,所以MD5结果相同;长字符串因为URL编码处理逻辑的差异,输入字节流完全不同,最终哈希结果自然不一致。
解决方案
你可以根据需求选择其中一种方式对齐两边的逻辑:
方式1:修改C#代码,先解码URL编码再计算MD5
如果需要和在线PHP服务的结果对齐,就在C#中先对输入字符串做URL解码,再转字节计算MD5。可以用WebUtility.UrlDecode(.NET Core/.NET 5+推荐)或HttpUtility.UrlDecode(传统.NET Framework):
public static string CreateMD5(string strInput) { // 先解码URL编码内容 string decodedInput = WebUtility.UrlDecode(strInput); using (MD5 md5 = MD5.Create()) { byte[] inputBytes = Encoding.UTF8.GetBytes(decodedInput); byte[] hashBytes = md5.ComputeHash(inputBytes); string hashedString = BitConverter.ToString(hashBytes).Replace("-", "").ToLower(); return hashedString; } }
方式2:让PHP直接计算原始字符串的MD5
如果要保持C#代码不变,那需要确保PHP不对输入做URL解码,直接用原始字符串计算MD5。比如在PHP中直接调用:
md5('test-server::7250406f7c43524545f794ff50dfd15b::name=%D0%98%D0%BD%D0%B5%D1%81%D1%81%D0%B0');
这样得到的结果就会和你原来的C#代码一致。
验证方法
你可以简单验证这个结论:
- 在C#中打印
Encoding.UTF8.GetBytes(strInput)的每个字节值,看看%D0%98部分对应的是0x25, 0x44, 0x30, 0x25, 0x39, 0x38。 - 在PHP中如果用
foreach(str_split($raw_str) as $c) echo ord($c).',';打印原始字符串的字节,会得到和C#一样的结果;但如果用foreach(str_split(urldecode($raw_str)) as $c) echo ord($c).',';,%D0%98部分会变成0xD0, 0x98,这就是差异所在。
内容的提问来源于stack exchange,提问作者Sam Alekseev
相关产品推荐
相关产品推荐

