朋友小张去面一个中级后端岗,技术面一路聊得挺顺,最后面试官随口问了一句:「用户密码你们怎么存数据库?」
小张脱口而出:「用MD5加密啊。」
面试官脸上的表情瞬间变了,草草又问了两个问题就结束了面试。后来小张跟我说:「早知道不答那么快了,感觉一道题就被判了死刑。」
说实话,这题不是面试官苛刻,而是安全底线题,答错真的没商量。
很多人以为MD5是"加密",其实它是哈希算法,而且是设计给校验文件完整性用的——不是给密码准备的。MD5最大的"罪过"是:算得太快。
有多快?普通GPU一秒钟可以算上百亿次MD5。这意味着什么?
一个8位纯小写字母密码(26^8 ≈ 2088亿种组合),暴力穷举只需要十几秒就能跑完。
更致命的是彩虹表——攻击者事先算好常用密码的MD5值,建一个"密码 → 哈希值"的反查表。你的数据库被拖库之后,攻击者拿着彩虹表一对比,明文密码直接暴露。
而且两个用户如果密码相同,MD5值也一模一样,一看就知道他们用的是同一个密码。这种确定性对于密码存储来说是灾难性的。
如果面试官追问「那你怎么改进MD5」,很多人会想到加盐。方向是对的,但这只是第一步。
加盐就是在密码后面拼一段随机字符串,然后一起哈希。这样每个用户的盐都不同,就算密码一样,哈希值也不一样,彩虹表直接失效。
但问题来了:MD5+盐 依然算得太快。攻击者虽然不能用彩虹表,但他可以针对你的数据库单独跑暴力破解——拿到盐之后,对每个常见密码拼上盐再算MD5。同样,一秒钟上百亿次,8位密码照样秒破。
加盐防的是彩虹表,防不了暴力破解。MD5的设计目标(快速)和密码存储的需求(缓慢)是根本矛盾的。
面试官真正想听的是慢哈希算法。这类算法的核心思想是:故意把计算变慢。
你登录的时候让它慢100毫秒完全没感觉,但攻击者暴力破解每个密码都要多花100毫秒,原来一秒钟能试10亿次的暴力破解,现在一秒钟只能试10次。这个差距是一亿倍。
目前业界公认的标准方案是 BCrypt:
cost 参数控制计算轮数,硬件升级了调高就行 用起来也极其简单:
# Python 示例
import bcrypt# 注册时 — 5行代码搞定
salt = bcrypt.gensalt(rounds=12)
hashed = bcrypt.hashpw(password.encode(), salt)# 登录时 — 3行搞定
bcrypt.checkpw(input_pw.encode(), stored_hash)除了BCrypt,其他几个主流慢哈希算法也值得了解:
面试推荐回答:「首选BCrypt,项目大的话考虑Argon2。」 这个答案既展示了知识广度,又体现了工程判断力。
面试官问密码怎么存,你可以这样组织回答:
💡 面试小技巧:提到「哈希升级策略」(旧密码逐步迁移到新算法)能加分不少,这说明了你有系统思维,不是只会调库。
密码存储这道题,面试官不是考你会不会调库,而是考你有没有安全底线意识。问到你这道题的时候:
其实这道题要是面试官问我,我会给他讲个真实的案例——
前几年有个知名社交平台被拖库,几亿用户的明文密码直接暴露在网上。你猜他们的密码存的是啥?就是MD5,连盐都没加。那事后补救就四个字:无力回天。
所以这道题与其说是考技术,不如说是考责任感——用户的密码交到你手上,你拿什么守好它?
···
你在面试中遇到过什么「一答就挂」的问题?评论区聊聊 👇