网站密码加盐的原理

密码哈希与加盐:从原理到实战

核心命题:假设数据库一定会被拖走,怎么让攻击者拿到也没用?

在本仓库中的位置

这是 Claude Code Vibe Coding 应用的架构分档手册 中「鉴权与支付」一节的深度展开。 任何 Tier ≥ 1 的应用,密码存储方案都要按本文执行。


一、为什么密码不能明文存?

❌ 明文存储
┌────────────────────────────────┐
│ 用户名     | 密码              │
│ albert    | 123456            │  ← 拖库 = 灾难
│ zhangsan  | qwerty            │
└────────────────────────────────┘

一旦数据库泄露(拖库),所有用户密码瞬间暴露。更糟的是用户常在多个网站用同一密码 → 一处泄露,处处沦陷(撞库攻击)。

📌 2011 年 CSDN 拖库事件,600 万账号明文密码泄露,引爆中国互联网密码安全意识。


二、第一层防御:哈希算法

哈希 = 单向的数学函数。

       hash()
"123456"  ───────►  e10adc3949ba59abbe56e057f20f883e
                    (永远是这个值,不可反推)

三大特性

特性含义
确定性同样输入 → 同样输出,永远成立
不可逆从哈希值反推不出原密码
雪崩效应输入变一点点,输出天差地别

雪崩效应直观感受

"123456"  ──►  e10adc3949ba59abbe56e057f20f883e
"123457"  ──►  f1887d3f9e6ee7a32fe5e76f4ab80d63
              ▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲
              完全没有规律可言

哈希到底怎么算的?(以 MD5 为例)

"123456"
   │
   ▼ 编码成二进制
[00110001 00110010 ...]
   │
   ▼ 填充到 512 位倍数
[512 位数据块]
   │
   ▼ 4 个魔法初值
A=0x67452301  B=0xefcdab89  C=0x98badcfe  D=0x10325476
   │
   ▼ 64 轮"揉面":AND / OR / XOR / 左旋 / 加常数
   │  每一轮:新B = B + 左旋(A + F(B,C,D) + M[i] + K[i], s)
   │
   ▼ 最终拼接 A|B|C|D
e10adc39 49ba59ab be56e057 f20f883e ✅

为什么不可逆? 因为大量使用了 AND / OR 这种有损运算——1 AND 0 = 0,但反过来你不知道原本是什么。


三、单纯哈希也不够:彩虹表攻击

攻击者会预先计算常见密码的哈希,做成超大对照表:

🌈 彩虹表(攻击者一次性投入几个月算好)
┌──────────────────────────────────────────────┐
│ 123456    →  e10adc3949ba59abbe56e057f20f883e│
│ password  →  5f4dcc3b5aa765d61d8327deb882cf99│
│ qwerty    →  d8578edf8458ce06fbc5bb76a58c5ca4│
│ ...(数十亿条)                               │
└──────────────────────────────────────────────┘

拖库 → 拿哈希 → 查表 → 瞬间还原 1000 万个密码 💀

“算一次表,破解所有人”——成本极低。


四、第二层防御:加盐(Salt)🧂

给每个用户生成随机字符串作为盐,拼到密码后再哈希:

注册流程
─────────────────────────────────────────────
用户输入:  "123456"
随机生成:  盐 = "x7Kp9mQ2"
计算:     hash("123456" + "x7Kp9mQ2") = a3f5b8c1...
存储:
┌──────────┬────────────┬──────────────┐
│ 用户名    │ 盐         │ 哈希          │
├──────────┼────────────┼──────────────┤
│ albert   │ x7Kp9mQ2   │ a3f5b8c1...  │
│ zhang    │ Lp4nR8wX   │ 9d2e7f4a...  │  ← 同样密码,盐不同,哈希也完全不同
└──────────┴────────────┴──────────────┘

关键认知颠覆 ⚠️

盐是公开存储的,不是秘密!

那加盐有什么用?看对比:

没加盐 🌈
─────────────
攻击者:算一次彩虹表 → 破解所有用户 ✅
成本:低

加盐后 🧂
─────────────
攻击者:每个用户盐不同
       → 用户1 算一张表(几个月)
       → 用户2 盐不一样,再算一张表(几个月)
       → 1000 万用户 = 1000 万张表 ❌
成本:彩虹表攻击经济上完全不可行

盐的作用不是"保密",而是"让批量破解失去经济意义"。


五、第三层防御:慢哈希算法

加盐后,攻击者还能针对单个用户暴力破解:

拿 albert 的盐 + 哈希
   ↓
试遍所有密码组合 → 找到匹配

普通 SHA-256 太快——GPU 一秒能算几十亿次

解决方案:故意把哈希算法设计得很慢

普通 SHA-256:    每秒 1,000,000,000 次  → 试遍 8 位密码只需几小时
bcrypt (cost=12): 每秒        300 次   → 同样的破解需要几百年
Argon2:          每秒        100 次   → 还要消耗大量内存,GPU 加速无效
算法特点推荐度
MD5 / SHA-1已破解,禁用
SHA-256太快,不适合密码
bcrypt经典,自带盐
scrypt抗 GPU/ASIC
Argon22015 密码哈希竞赛冠军⭐ 首选

对单次登录用户无感(0.1 秒),对暴力破解者来说成本提高几亿倍。


六、第四层防御:Pepper(胡椒)🌶️

如果想再加一层——

Salt(盐)Pepper(胡椒)
存哪里数据库,和哈希一起应用代码 / 环境变量 / KMS
每用户不同全局共用一个
拖库会泄露吗不会(除非服务器也被入侵)
hash = Argon2(密码 + 盐 + Pepper)
                          ▲
                          └── 不进数据库,藏在应用层

双层物理隔离:要破解必须同时攻破数据库 + 应用服务器。

💡 落到你的真实环境

Pepper 应该存在哪?参考你已经在用的两台服务器 —— 阿里云服务器代码资产盘点-2026-04-23 与 云服务器代码资产盘点-2026-04-23 推荐做法:写进各服务的 systemd Environment 文件 / .envchmod 600绝不进 Git;如果上了阿里云 KMS,就用 KMS 凭据 API 拉取。


七、完整防御链总览

                密码安全分层防御 🛡️
   ┌─────────────────────────────────────────┐
   │                                         │
   │   ┌──────────────────────────────────┐  │
   │   │  ❌ 明文                         │  │   拖库 = 死
   │   └──────────────────────────────────┘  │
   │                  ⬇                       │
   │   ┌──────────────────────────────────┐  │
   │   │  🔒 哈希  防明文裸奔              │  │   防彩虹表?❌
   │   └──────────────────────────────────┘  │
   │                  ⬇                       │
   │   ┌──────────────────────────────────┐  │
   │   │  🔒 + 🧂 加盐  防彩虹表           │  │   防暴力?⚠️
   │   └──────────────────────────────────┘  │
   │                  ⬇                       │
   │   ┌──────────────────────────────────┐  │
   │   │  🔒 + 🧂 + 🐌 慢算法  防暴力破解  │  │   防服务器入侵?⚠️
   │   └──────────────────────────────────┘  │
   │                  ⬇                       │
   │   ┌──────────────────────────────────┐  │
   │   │  🔒+🧂+🐌+🌶️ Pepper  分层隔离    │  │   ✅ 现代最佳实践
   │   └──────────────────────────────────┘  │
   └─────────────────────────────────────────┘

注册流程

用户密码 ──► 生成随机盐 ──► Argon2(密码 + 盐 + Pepper) ──► 入库
                                                  ┌────────────────┐
                                                  │ 用户 | 盐 | 哈希 │
                                                  └────────────────┘

登录流程

用户输入 ──► 查出该用户的盐 ──► Argon2(密码 + 盐 + Pepper) ──► 比对哈希
                                                              ↓
                                                          相等 → 登录成功
                                                          不等 → 拒绝

八、相关攻击术语

术语含义
拖库攻击者把整个数据库下载走
洗库在拖到的数据中筛选高价值信息(VIP、管理员等)
撞库用 A 网站泄露的密码去 B/C/D 网站尝试登录
彩虹表预先计算的"密码 → 哈希"对照表
碰撞攻击找到两个不同输入产生同一哈希值(MD5 已被攻破)

九、给开发者的实践清单

  • 永远不要自己实现密码哈希算法
  • 使用成熟库:Python passlib / Node bcrypt / Rust argon2 crate
  • 首选 Argon2id,备选 bcrypt(cost ≥ 12)
  • 盐至少 16 字节,密码学安全的随机数生成器生成(不要用 Math.random()
  • Pepper 存在环境变量或 KMS,永不进代码仓库
  • 配套措施:登录失败次数限制、2FA、异常登录告警
📝 在你已有项目里落地

给Hermes Agent装上Open WebUI:从零到一的完整实践 中如果开放了用户登录, 建议把默认 Open WebUI 的密码哈希策略升级为 Argon2id + Pepper。 而 Claude Code Vibe Coding 应用的架构分档手册 的 Tier 0 → Tier 1 升级时, Auth.js / Clerk 默认已用 bcrypt,如果走自管 session 就要手动选算法。

十、给用户的自保清单

  • 不在多个网站用同一密码(用 Bitwarden / KeePass 等密码管理器)
  • 重要账户开启 2FA / TOTP(Google Authenticator、Authy)
  • 定期上 haveibeenpwned.com 查邮箱是否在已知泄露库
  • 长密码 > 复杂密码(correct horse battery staple > P@ssw0rd!
💡 移动端体验小贴士

wiki-iphone-pwa-使用指南-2026-05-02 里提到的 PWA 形态, 配合 iOS Keychain / Face ID 可以做到长密码 + 一键登录两不误, 是用户侧自保清单的最佳工程实现。


一句话总结

哈希防明文裸奔,加盐防彩虹表,慢算法防暴力破解,Pepper 防数据库单点失陷。 现代密码学不追求"绝对安全",而是让攻击成本翻几个数量级,最终让攻击者放弃。


🔗 本仓库相关笔记

强相关(同一架构链路)

  • Claude Code Vibe Coding 应用的架构分档手册 —— 鉴权与支付一节的纵向展开
  • 阿里云服务器代码资产盘点-2026-04-23 —— Pepper / KMS 实际落地的服务器
  • 云服务器代码资产盘点-2026-04-23 —— 同上,多机部署时同步 Pepper

中等相关(应用层接入)

知识体系入口

占位(待补建的笔记)

  • 数据库安全
  • Web 安全基础
  • OWASP Top 10
  • 2FA 与 TOTP 原理
  • KMS 密钥管理服务

%% 整理日期: 2026-05-05 · 来源: Downloads/网站密码加盐的原理.md,已嵌入领域库双向链接 %%

Powered by Obsidian + Hugo
使用 Hugo 构建
主题 StackJimmy 设计