当前位置: 首页> 最新文章列表> PHP 中 md5 和 sha1 有啥区别?哈希函数对比分析指南

PHP 中 md5 和 sha1 有啥区别?哈希函数对比分析指南

gitbox 2025-09-19

本文面向想在 PHP 中理解并正确应用哈希函数的开发者。我们将对比 MD5 和 SHA-1,从原理、输出、抗碰撞性、速度、典型用途以及在 PHP 中的实际用法给出清晰、务实的建议,并说明更安全的替代方案与使用注意事项。

一、基本概念回顾(非常简短)

  • 哈希(散列)函数:接受任意长度输入,输出固定长度的“摘要”。常用于校验数据完整性、生成签名基础、做索引等。

  • 不可逆性:哈希函数应是单向的——理论上不能从摘要反推出原始输入(但并非绝对,取决于攻击者能力)。

  • 碰撞:不同输入产生相同输出的情况。理想哈希应难以找到碰撞。

二、MD5 与 SHA-1 的技术规格对比

  • 输出长度

    • MD5:128 位,通常以 32 字符十六进制表示(如 d41d8cd98f00b204e9800998ecf8427e)。

    • SHA-1:160 位,通常以 40 字符十六进制表示(如 da39a3ee5e6b4b0d3255bfef95601890afd80709)。

  • 安全性(摘要)

    • MD5:已被证明存在实际可行的碰撞攻击,不能用于安全敏感场景(签名、证书、密码存储等)。

    • SHA-1:比 MD5 强,但也已被实证破解(研究/实验证明可找到碰撞),已被逐步弃用作为安全哈希。

  • 速度

    • MD5 通常比 SHA-1 更快(更短的内部状态与运算量更少),但速度差异在现代硬件上不是主要考量——安全性更重要。

三、在 PHP 中的基本用法(示例)

<span><span><span class="hljs-meta">&lt;?php</span></span><span>
</span><span><span class="hljs-variable">$data</span></span><span> = </span><span><span class="hljs-string">"hello world"</span></span><span>;

</span><span><span class="hljs-comment">// MD5</span></span><span>
</span><span><span class="hljs-variable">$md5</span></span><span> = </span><span><span class="hljs-title function_ invoke__">md5</span></span><span>(</span><span><span class="hljs-variable">$data</span></span><span>);         </span><span><span class="hljs-comment">// 32 hex</span></span><span>
</span><span><span class="hljs-variable">$md5_raw</span></span><span> = </span><span><span class="hljs-title function_ invoke__">md5</span></span><span>(</span><span><span class="hljs-variable">$data</span></span><span>, </span><span><span class="hljs-literal">true</span></span><span>); </span><span><span class="hljs-comment">// 原始二进制 16 字节</span></span><span>

</span><span><span class="hljs-comment">// SHA-1</span></span><span>
</span><span><span class="hljs-variable">$sha1</span></span><span> = </span><span><span class="hljs-title function_ invoke__">sha1</span></span><span>(</span><span><span class="hljs-variable">$data</span></span><span>);       </span><span><span class="hljs-comment">// 40 hex</span></span><span>
</span><span><span class="hljs-variable">$sha1_raw</span></span><span> = </span><span><span class="hljs-title function_ invoke__">sha1</span></span><span>(</span><span><span class="hljs-variable">$data</span></span><span>, </span><span><span class="hljs-literal">true</span></span><span>); </span><span><span class="hljs-comment">// 原始二进制 20 字节</span></span><span>

</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"MD5: <span class="hljs-subst">$md5</span></span></span><span>\n";
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"SHA1: <span class="hljs-subst">$sha1</span></span></span><span>\n";
</span></span>

对于需要用密钥的消息认证(更安全的完整性校验),请使用 HMAC:

<span><span><span class="hljs-meta">&lt;?php</span></span><span>
</span><span><span class="hljs-variable">$key</span></span><span> = </span><span><span class="hljs-string">"secret-key"</span></span><span>;
</span><span><span class="hljs-variable">$data</span></span><span> = </span><span><span class="hljs-string">"important payload"</span></span><span>;

</span><span><span class="hljs-comment">// 推荐使用更长更安全的哈希(示例:sha256)</span></span><span>
</span><span><span class="hljs-variable">$hmac</span></span><span> = </span><span><span class="hljs-title function_ invoke__">hash_hmac</span></span><span>(</span><span><span class="hljs-string">'sha256'</span></span><span>, </span><span><span class="hljs-variable">$data</span></span><span>, </span><span><span class="hljs-variable">$key</span></span><span>);
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"HMAC-SHA256: <span class="hljs-subst">$hmac</span></span></span><span>\n";
</span></span>

四、典型用途与风险

  • 仅做非安全性唯一标识 / 快速校验(小风险可接受)

    • MD5 或 SHA-1 都可用于生成文件名哈希、简单的缓存键、去重的快速判断(但不能依赖为强一致性保证)。

  • 用于安全敏感场景(绝对不推荐)

    • 密码存储、数字签名、TLS/证书指纹、签名验证等:不要使用 MD5/ SHA-1。两者都存在实用的碰撞攻击(尤其 MD5),攻击者可伪造相同摘要的不同消息。

  • 文件完整性校验

    • 若只是防止传输时意外损坏(非对抗者场景),MD5/SHA-1 仍常见于文件下载页。但若担心恶意篡改,请用更强的哈希(SHA-256/512)或签名(HMAC/公私钥签名)。

五、已知攻击(概要)

  • MD5:自 2000 年代早期以来出现多种碰撞攻击和实用攻击,已被广泛弃用用于安全用途。

  • SHA-1:长期被认为比 MD5 更安全,但研究与实验证明存在实用碰撞(例如学术界在 2017 年公布的实用碰撞演示),因此在安全性要求高的场合也应避免使用。

(备注:以上为概述性说明,已公开的研究和工实践表明两者在抵抗碰撞方面不足。)

六、推荐做法(PHP 实践建议)

  1. 密码永远使用专门的密码散列函数:使用 password_hash() / password_verify(),PHP 默认(PASSWORD_DEFAULT)会使用现代安全算法(如 bcrypt 或更好的实现),并自动处理随机盐与成本因子。

    <span><span><span class="hljs-meta">&lt;?php</span></span><span>
    </span><span><span class="hljs-comment">// 密码哈希与验证(示例)</span></span><span>
    </span><span><span class="hljs-variable">$password</span></span><span> = </span><span><span class="hljs-string">'user-password'</span></span><span>;
    </span><span><span class="hljs-variable">$hash</span></span><span> = </span><span><span class="hljs-title function_ invoke__">password_hash</span></span><span>(</span><span><span class="hljs-variable">$password</span></span><span>, PASSWORD_DEFAULT);
    </span><span><span class="hljs-comment">// 存储 $hash 到数据库</span></span><span>
    </span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">password_verify</span></span><span>(</span><span><span class="hljs-variable">$password</span></span><span>, </span><span><span class="hljs-variable">$hash</span></span><span>)) {
        </span><span><span class="hljs-comment">// 验证通过</span></span><span>
    }
    </span></span>
  2. 消息完整性与认证用 HMAC 或签名:对对抗环境请使用 hash_hmac()(例如用 sha256sha512),或使用公钥签名(openssl_sign 等):

    <span><span><span class="hljs-meta">&lt;?php</span></span><span>
    </span><span><span class="hljs-variable">$tag</span></span><span> = </span><span><span class="hljs-title function_ invoke__">hash_hmac</span></span><span>(</span><span><span class="hljs-string">'sha256'</span></span><span>, </span><span><span class="hljs-variable">$message</span></span><span>, </span><span><span class="hljs-variable">$secret_key</span></span><span>);
    </span></span>
  3. 一般哈希首选 SHA-2 或 SHA-3 系列:例如 sha256sha512,在 PHP 中可通过 hash('sha256', $data)hash('sha512', $data) 使用;这些在强度上显著好于 MD5/SHA-1。

  4. 若需要对二进制更高效处理,可使用原始二进制输出md5($data, true) / sha1($data, true)),并对结果做 base64 编码存储或传输。

  5. 不要试图“用盐+多次哈希”自己造密码哈希方案:容易出错、难以维护。请使用语言/框架推荐的密码散列 API。

七、对比小结(简明表)

  • 输出长度:MD5 = 128 位(32 hex),SHA-1 = 160 位(40 hex)。

  • 安全性:SHA-1 > MD5,但两者都不再适合安全关键场景。

  • 速度:MD5 略快,但差异不应成为选用标准(安全性优先)。

  • 推荐用途:仅用于非安全的唯一标识或兼容场景;安全用途请用 SHA-2/SHA-3/HMAC/password_hash。

八、实际选择建议(一句话)

如果你在写新代码并且关心安全性,不要使用 MD5 或 SHA-1 —— 用 hash('sha256', $data) / hash_hmac('sha256', $data, $key) 做完整性与认证,用 password_hash() 管理密码;只有在兼容历史系统或对安全无关的场景下才考虑 MD5/SHA-1。