是什么

哈希函数(Hash Function):把任意长度的输入,映射成固定长度的输出(哈希值/摘要)。

密码学哈希的性质

一个安全的密码学哈希函数应满足:

一、确定性:相同输入永远得到相同输出。

二、单向性(抗原像性):从哈希值无法(在计算上)反推出原始输入。

三、抗碰撞性:很难找到两个不同的输入,使它们的哈希值相同。

四、雪崩效应:输入的微小改变(哪怕一个比特),会导致输出发生巨大改变(约一半的比特翻转)。

五、计算高效:正向计算很快。

常见算法

算法输出长度状态
MD5128 bit已不安全,不应使用
SHA-1160 bit已不安全,不应使用
SHA-256256 bit安全,广泛使用
SHA-3可变安全,较新的标准
BLAKE2/3可变安全,速度快

重要:MD5 和 SHA-1 都已被证实可以构造碰撞(2004 年 MD5 被破解,2017 年 Google 公布了 SHA-1 的实际碰撞攻击 "SHAttered")。

它们不应再用于任何安全场景。

主要用途

一、密码存储

绝不能明文存储密码!

正确做法:存储密码的哈希值。用户登录时,计算输入密码的哈希,与数据库中存储的哈希比对。

但仍不够——因为攻击者可以用彩虹表(预先计算好的常见密码哈希表)反查。

必须加盐(Salt):

  1. 为每个用户生成一个随机盐值;
  2. 把盐与密码拼接后哈希;
  3. 存储盐和哈希值。

这防止了彩虹表攻击(因为每个用户的盐不同,攻击者必须为每个用户单独计算)。

更进一步:用慢哈希函数(专门设计的、计算昂贵的算法)。

  • bcrypt、scrypt、Argon2 是推荐的密码哈希算法;
  • 它们被设计成故意慢且消耗内存,从而大幅提高暴力破解的成本。

Argon2 是 2015 年密码哈希竞赛的获胜者,是目前推荐的选择。

注意:普通的 SHA-256 计算太快,不适合直接用于密码存储——GPU 每秒可以计算数十亿次。

二、数据完整性校验

下载文件时提供的校验值(checksum),用于验证文件在传输中没有被损坏或篡改。

不过,单纯的哈希不能防止恶意篡改——因为攻击者可以同时修改文件和哈希值。防篡改需要数字签名或 HMAC。

三、数字签名

对消息的哈希值签名,而非对整条消息签名——因为哈希值长度固定且短,效率高。

四、去重与数据结构

  • 哈希表:用哈希函数快速定位数据(前文提到过);
  • 去重:比较哈希值而非比较完整数据;
  • 布隆过滤器:用多个哈希函数实现高效的"可能存在"判断(内存占用极小,可能有假阳性但无假阴性)。

五、区块链与工作量证明

区块链用哈希函数构建链式结构(每个区块包含前一个区块的哈希),并用哈希计算作为工作量证明的基础。

六、内容寻址

内容寻址存储(如 IPFS、Git):用内容的哈希作为标识符。

Git 就是这样——每个对象(文件、目录、提交)都由其内容的哈希(SHA-1)标识。这意味着相同内容只会存储一次,且任何修改都会被检测到。

注意:Git 使用 SHA-1 不是为了防碰撞攻击(它主要用于完整性检测,而非安全签名),但 Git 社区也在向 SHA-256 迁移。

非密码学哈希

不是所有哈希都用于安全:

  • CRC32:错误检测(如网络传输、压缩文件),不抗恶意篡改;
  • MurmurHash、CityHash、xxHash:为速度优化,用于哈希表等非安全场景。

不要用非密码学哈希处理安全相关的数据。

说明:本文为密码学基础的知识整理。