密码安全那些事:从明文到 SHA-256 到 BCrypt,为什么一步步升级

密码安全那些事:从明文到 SHA-256 到 BCrypt,为什么一步步升级 核心问题为什么密码不能直接存假设你的数据库里用户表长这样user_idusernamepassword1zhangsan1234562lisiabcdef如果数据库被黑客拖走了这叫拖库所有用户的密码直接暴露。用户很多时候多个网站用同一个密码一个库泄露其他网站的账号也跟着遭殃。所以我们需要把密码加工一下再存即使数据库泄露黑客也拿不到原始密码。第一步MD5MD5 是最早被广泛使用的哈希算法。哈希的意思就是给一个输入算出一个固定长度的乱码而且这个过程不可逆——你没办法从乱码反推出原始内容。123456 → MD5 → e10adc3949ba59abbe56e057f20f883e abcdef → MD5 → e80b5017098950fc58aad83c8c14978e现在数据库里存的是这串乱码不是明文了。用户登录时把他输入的密码也做一次 MD5跟数据库里的比对一样就说明密码正确。看起来安全了问题来了。MD5 的致命缺陷同样的输入永远得到同样的输出。黑客早就把常见密码的 MD5 值算好了做成一张巨大的表叫彩虹表123456 → e10adc3949ba59abbe56e057f20f883e password → 5f4dcc3b5aa765d61d8327deb882cf99 qwerty → d8578edf8458ce06fbc5bb76a58c5ca4 ...几十亿条拿到数据库里的哈希值直接查表就能反查出原始密码。MD5 基本等于裸奔。第二步加盐Salt既然问题出在同样的密码产生同样的哈希那我们在密码后面拼一段随机字符串再做哈希这段随机字符串就叫盐salt。用户密码123456 随机盐值x7k9m2 实际哈希的内容123456x7k9m2每个用户的盐值都不一样所以即使两个用户密码都是 123456存到数据库里的哈希值也完全不同user_idpassword_hashsalt1a3f2b8c9...x7k9m227d1e4f5a...p3q8n1这样彩虹表就废了因为黑客不可能提前算出所有密码盐的组合。第三步SHA-256MD5 本身也有问题——它太快了而且已经被发现存在碰撞两个不同的输入可能算出相同的哈希值。所以后来大家换成了更强的哈希算法SHA-256 就是其中一个。SHA-256 输出 64 个十六进制字符比 MD5 的 32 个更长安全性更高123456 → SHA-256 → 8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92现在很多项目里用的就是 SHA-256 加盐。流程是存密码SHA-256(明文密码 盐) → 存哈希值和盐 验密码SHA-256(用户输入 数据库里的盐) → 跟数据库里的哈希值比对这已经比 MD5 好很多了但还有一个问题。SHA-256 的隐患它还是太快了。现在的 GPU 一秒钟能算几十亿次 SHA-256。黑客拿到你的盐值后可以暴力穷举——把所有可能的密码组合都试一遍这叫暴力破解。密码短一点的几小时就能破。第四步BCryptBCrypt 专门为密码存储设计它解决了上面所有问题自带盐不用你自己生成和管理盐值BCrypt 自动生成并嵌入到结果里故意很慢BCrypt 有一个工作因子cost factor可以控制计算速度。默认是 10意味着内部会做 2^10 1024 轮运算。调到 12 就是 4096 轮越高越慢慢有什么好处你正常登录验证一次慢个 0.1 秒用户完全无感。但黑客要暴力破解几十亿次每次都要 0.1 秒直接从几小时变成几百年。BCrypt 的输出长这样$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy拆开看$2a$算法版本10$工作因子cost 10N9qo8uLOickgx2ZMRZoMye盐值自动生成的IjZAgcfl7p92ldGxad68LJZdL17lhWy哈希值盐和哈希值存在一起验证的时候 BCrypt 自己会把盐提取出来你什么都不用管。在 Spring Boot 里用起来非常简单// 加密 BCryptPasswordEncoder encoder new BCryptPasswordEncoder(); String hash encoder.encode(123456); // 每次调用结果都不一样因为盐是随机的 // 验证 boolean match encoder.matches(123456, hash); // true boolean wrong encoder.matches(654321, hash); // false总结一下演进过程明文存储 → 数据库泄露就全完了 ↓ MD5 → 彩虹表直接反查 ↓ MD5 盐 → 彩虹表废了但 MD5 有碰撞问题 ↓ SHA-256 盐 → 更安全但速度太快暴力破解扛不住 ↓ BCrypt → 自带盐 故意慢暴力破解成本极高写到这里整条演进线就很清晰了每一次升级都不是为了炫技而是上一代方案被实实在在地攻破了才不得不往前走一步。明文太裸MD5 被彩虹表打穿加盐挡住了查表但挡不住暴力跑SHA-256 快是优点也是缺点最后 BCrypt 用故意慢这个反直觉的思路把问题兜住了。下次面试官问你密码怎么存别直接蹦 BCrypt。从明文开始讲一步步说清楚每个方案解决了什么、又留下了什么比背一个标准答案有说服力得多。