哈希——它是什么,加密算法及应用

作者: IT Sectr 发布日期: 2026-04-02 阅读时间: 8 分钟

哈希是将任意大小的数据转换为固定长度字符串的过程,用于检查完整性和安全存储密码。根据Open Web Application Security Project (OWASP, 2025),正确使用哈希函数可以防止驶证据泄露相关漏洞的70%。加密哈希是数字签名、区块链技术和版本控制的基础。

要点

  • 哈希函数将输入数据转换为固定长度的字符串——摘要。
  • 加密哈希具有不可逆性:无法从哈希恢复原始数据。
  • SHA-256——NIST为现代系统推荐的加密哈希标准。
  • ——在哈希之前添加到密码中的随机数据,用于防御彩虹表攻击。
  • 哈希在移动应用中广泛用于存储密码和检查数据完整性。

什么是哈希?

哈希——计算哈希函数的过程,该函数将任意输入数据集转换为固定长度的比特串,称为摘要或哈希值。与加密不同,哈希是一个单向过程:无法从哈希恢复原始数据。

哈希函数的基本属性

加密哈希函数具有四个必要属性:确定性(相同的输入始终产生相同的哈希)、不可逆性(从计算上无法从哈希恢复输入)、雪崩效应(输入中一个比特的变化平均改变哈希的一半比特)和抵御碰撞(从计算上无法找到两个不同的输入产生相同的哈希)。

哈希与加密的区别

理解哈希与加密之间的区别很重要。加密是一个双向过程:加密数据可以用密钥解密。哈希是一个单向过程:转换后数据无法恢复。这一属性使哈希成为存储密码的理想方式:系统只存储哈希,即使数据库泄露,密码也会受到保护。

加密和非加密哈希函数

并非所有哈希函数都同样适合安全任务。在选择移动开发中特定任务的算法时,将其分为加密和非加密类别至关重要。

加密哈希函数

这些函数故意设计得缓慢且复杂,以增加暴力破解攻击的难度。它们必须抵御碰撞和预像攻击。SHA-2家族(SHA-224、SHA-256、SHA-384、SHA-512)已获得NIST认证,并被推荐用于政府系统。对于密码哈希,还使用bcrypt、scrypt和Argon2等算法,具有可配置的复杂度

非加密哈希函数

这些函数优化于速度而非安全性。示例:CityHash、MurmurHash、xxHash。它们用于哈希表、数据去重和校验和,以快速检查非关键数据的完整性。切勿将它们用于存储密码或验证数字签名——高速使它们容易受到暴力破解攻击。

类型示例应用领域
加密SHA-256, SHA-3, bcrypt密码、签名、TLS
非加密MurmurHash, xxHash哈希表、缓存
密码KDFbcrypt, scrypt, Argon2密码存储

让我们看看现代移动开发中最常用的哈希算法。每一种都有其优缺点。

SHA-256

SHA-256——现代加密的象征,由NIST在FIPS 180-4标准框架内推荐。该算法产生256位摘要,是TLS协议、区块链网络和版本控制系统的主要组成部分。根据NCC Group(2025)报告,SHA-256用于96%的TLS证书签名,用于签署证书透明度。

SHA-3——SHA-2的后继者

SHA-3——NIST于2015年作为FIPS 202标准化的最新哈希函数家族。与基于Merkle–Damgård结构的SHA-2不同,SHA-3基于不同的Keccak构造,采用海绵函数。这使得SHA-3能够抵御未来可能出现在SHA-2上的攻击。对于移动开发者,SHA-3可通过标准加密库从Android 7.0和iOS 13开始使用。

kotlin
import java.security.MessageDigest

fun hashWithSHA256(input: String): String {
    val digest = MessageDigest.getInstance("SHA-256")
    val hashBytes = digest.digest(input.toByteArray())
    return hashBytes.joinToString("") { String.format("%02x", it) }
}

bcrypt对于密码

对于存储密码,普通的加密哈希不够用——它们太快了。bcrypt是专门为密码哈希设计的:它包含盐和用于调节计算时间的成本参数。将成本提高2倍会使哈希时间翻倍,使暴力破解攻击即使在强大硬件上也无效

kotlin
import at.favre.lib.crypto.bcrypt.BCrypt

fun hashPassword(password: String): String {
    return BCrypt.create()
        .hashToString(BCrypt.MIN_COST, password.toCharArray())
}

fun verifyPassword(password: String, hash: String): Boolean {
    val result = BCrypt.verifyer().verify(password.toCharArray(), hash)
    return result.verified
}

Argon2——现代标准

Argon2——Password Hashing Competition(2015)的冠军,被OWASP推荐为密码哈希的最佳选择。Argon2id——能抵御侧通道攻击和时间-内存权衡攻击的变体。与bcrypt不同,Argon2允许单独配置执行时间、内存使用和并行程度,为各种类型的攻击提供灵活的保护。

哈希在移动应用中的应用

哈希在移动开发中解决许多实际问题——从用户认证到检查下载文件的完整性。让我们看看主要的使用场景。

密码存储

主要场景——在服务器端安全存储密码。注册时,应用将密码发送到服务器,在那里用bcrypt或Argon2算法加盐哈希并存储在数据库中。登录时,服务器哈希输入的密码并与存储的哈希进行比较。OWASP推荐使用Argon2id,参数如下:时间2秒,内存64 MB,并行程度4。

文件完整性检查

在下载大型文件(如OBB包或内容更新)时,移动应用可以通过哈希检查其完整性。服务器公布文件的SHA-256哈希,应用计算下载数据的哈希并进行比较。这保证文件在传输过程中未受损或被替换。根据Google Play Console(2025),认证应用的哈希验证可防止达99.9%的损坏下载攻击。

缓存和去重

哈希被广泛用于构建高效缓存和数据去重。图片地址或JSON响应被哈希并用作缓存键:在重复请求时,系统比较哈希,如果数据未变,则返回存储的结果。对于这一任务,适合使用MurmurHash或xxHash等非加密哈希函数,它们提供最佳性能。

kotlin
import java.security.MessageDigest

fun calculateFileHash(fileBytes: ByteArray): String {
    val digest = MessageDigest.getInstance("SHA-256")
    val hash = digest.digest(fileBytes)
    return hash.joinToString("") { String.format("%02x", it) }
}

fun verifyIntegrity(data: ByteArray, expectedHash: String): Boolean {
    val actualHash = calculateFileHash(data)
    return actualHash == expectedHash
}

使用哈希时的常见错误

即使是经验丰富的开发者在使用哈希时也会犯错误。让我们看看最常见的问题,这些问题可能使加密保护的所有优势化为乌有。

使用MD5或SHA-1

MD5和SHA-1——过时的算法,已有实用的碰撞攻击。MD5于2004年被一组中国研究者破解(一小时内碰撞)。SHA-1于2017年被Google和Centrum Wiskunde & Informatica团队破解(SHAttered攻击)。根据OWASP分类,在新项目中使用这些算法被视为严重安全错误

无盐哈希

哈希密码——致命漏洞。盐是一个随机字符串,对每个用户唯一,在哈希之前添加到密码中。没有盐,两个相同的密码将产生相同的哈希,这使得攻击者可以使用彩虹表进行暴力破解。OWASP推荐使用加密强盐,长度至少32字节,为每个用户单独生成。

迭代次数不足

即使使用bcrypt或Argon2,选择过低的成本参数也会削弱保护。根据OWASP(2025),bcrypt的最小迭代次数应为10(2^10 = 1024次迭代),Argon2id在目标平台上的计算时间至少1秒。过低的参数使暴力破解攻击在GPU农场上实际可行

常见问题

哈希和加密有什么区别?

哈希——单向过程,结果无法转换回原始数据。加密是双向过程:加密数据可以用密钥解密。哈希用于密码存储和完整性检查,加密用于客户端和服务器之间数据的保密传输

哪种哈希算法最适合密码?

OWASP推荐Argon2id作为密码哈希的最佳选择,因其可配置的GPU攻击和侧通道攻击防护。替代方案:bcrypt(经过验证且容易配置)、scrypt(抵御ASIC攻击)和PBKDF2。SHA-256和SHA-512不适合密码——它们太快,无法防御大规模暴力破解。

什么是哈希函数碰撞,为什么危险?

碰撞——两个不同的输入数据集产生相同哈希的情况。对于加密哈希函数,寻找碰撞必须从计算上不可能。例如,SHA-256对于两个随机消息的碰撞概率约为二分之一的128次方分之一——这是一个微乎其微的数值。

需要手动向bcrypt添加盐吗?

不需要,bcrypt自动将盐包含在其算法中。调用BCrypt.hashToString()时,库会生成16字节的加密强盐,并将其与哈希和成本参数一起嵌入输出字符串。Scrypt和Argon2也类似工作。这是专家建议使用专用KDF而非普通哈希函数来保护密码的原因之一。

可以使用哈希来防御恶意软件吗?

可以,哈希用于创建文件的白名单和黑名单。防病毒数据库包含已知恶意软件的哈希。但攻击者可以修改程序中的一个字节,这将完全改变哈希。因此,现代系统使用模糊哈希(SSDeep、TLSH),它们发现语义相似的文件,而不仅仅是精确匹配。

总结

  • 哈希——将数据单向转换为固定长度字符串,保证不可逆。
  • 加密哈希函数提供碰撞抵御和雪崩效应。
  • SHA-256——现代系统中加密哈希的NIST标准。
  • 密码KDF(bcrypt、Argon2、scrypt)对于安全密码存储是必不可少的。
  • 防御彩虹表攻击,并应对每个用户唯一。
  • MD5和SHA-1被视为已破解,不应在新项目中使用。
  • 哈希用于密码存储、数据完整性检查、缓存和防病毒保护。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读