服务器帮你验证密码,但它连你密码的哈希值都不知道。OPAQUE 实现了密码安全的圣杯。

前情回顾:SRP 的遗憾

在上一篇中,我们介绍了 SRP 协议。它已经很强大了:

  • ✅ 密码不在网络上传输
  • ✅ 服务器不知道真实密码
  • ✅ 监听者无法窃取密码

但 SRP 有一个隐藏的弱点:服务器存储的"验证器"仍然与密码直接相关

SRP 存储的验证器v = g^(H(salt, password)) mod N ← 直接由密码派生

如果数据库泄露

攻击者获得 salt 和 v 后,可以离线暴力破解:

for password in wordlist:
    x = H(salt, password)
    v_guess = pow(g, x, N)
    if v_guess == v:
        print("Found:", password)
        break

不需要服务器参与,攻击者可以在自己的机器上无限尝试。虽然离散对数难题增加了计算成本,但这仍是"离线"攻击!

OPAQUE 的野心

OPAQUE(2018年提出,2023年成为IETF标准草案)的目标更加激进:

即使服务器数据库完全泄露,攻击者也无法离线破解密码。

怎么做到的?答案是:服务器自己都不知道验证器是怎么算出来的!

一个脑洞大开的类比

想象一个特殊的"蒙眼锁匠"场景:

背景设定

你有一个保险箱,钥匙的制作方法很特殊:

  • 钥匙 = 你的秘密配方 + 锁匠的独门手法
  • 两者缺一不可

SRP 方案的问题

你用配方自己做了钥匙,把钥匙的"形状参数"告诉锁匠存档。

问题:如果锁匠的档案室被盗,小偷拿到"形状参数"后,可以在自己家里疯狂尝试各种配方,看哪个能做出相同形状的钥匙。每秒试十亿次,总能试出来。

OPAQUE 方案

制作钥匙的过程

  1. :把配方变成一团神秘材料(你自己也不认识了)
  2. 你 → 锁匠:传递神秘材料(双方都不知道里面是什么)
  3. 锁匠:用独门手法加工材料(不知道原料是什么)
  4. 锁匠 → 你:传回加工后的材料
  5. :去掉神秘外壳,得到最终钥匙 = 配方 + 手法

结果

  • 你知道配方,但不知道手法
  • 锁匠知道手法,但不知道配方
  • 钥匙 = 配方 + 手法,双方都无法独立制作!

如果小偷偷了锁匠的档案室?

小偷偷到了什么?

锁匠的档案室:

  • 用户 Alice 的 “加工后材料”
  • 用户 Bob 的 “加工后材料”

但是:这些"加工后材料"已经混合了锁匠的手法,没有手法,就无法还原出原始配方!

小偷想暴力破解:

  1. 遍历所有可能的配方
  2. 把配方"神秘化"
  3. 加工?→ 需要锁匠的手法!无法继续!

每次尝试都必须请锁匠帮忙加工,但锁匠会记录尝试次数,超过限制就锁定账户!

对比

方案破解方式速度
SRP离线破解每秒 10 亿次 → 弱密码几分钟破解
OPAQUE在线破解受服务器限流(每分钟 5 次)、3 次失败锁定账户

这就是 OPAQUE 的革命性突破:把暴力破解从"离线"逼到"在线"。

OPAQUE 的两个关键技术

1. OPRF:双盲计算

OPRF(Oblivious Pseudo-Random Function,不经意伪随机函数)是 OPAQUE 的核心黑科技。

普通哈希 (如 Argon2)

  • 输入: password
  • 输出: H(password)
  • 特点: 任何人都能算,只需要知道密码

OPRF

  • 输入: password (客户端持有) + key (服务器持有)
  • 输出: F(key, password)
  • 特点:
    • 客户端不知道 key → 无法独立计算
    • 服务器不知道 password → 不知道在计算什么
    • 双方合作才能得到结果

神奇之处:服务器帮你计算,却不知道你算的是什么!

这听起来像悖论?让我解释:

  1. 客户端盲化blind = H(pwd)^r(用随机数 r 遮住密码)
  2. 客户端 → 服务器:发送 blind
  3. 服务器计算result = blind^key
  4. 服务器 → 客户端:返回 result
  5. 客户端去盲化output = result^(1/r) = H(pwd)^key

数学魔法

  • blind = H(pwd)^r
  • result = blind^key = H(pwd)^(r*key)
  • output = result^(1/r) = H(pwd)^key ← r 被消掉了!

结果

  • 客户端得到 H(pwd)^key
  • 服务器只看到了 blind (被 r 遮住的值)
  • 服务器无法从 blind 推出 password
  • 每次的 r 都不同,服务器无法关联多次请求

这就像一个神奇的翻译机器

  • 你把密码用密码本 A 加密后发过去
  • 服务器用它的密码本 B 再加密一次后发回来
  • 你用密码本 A 解密
  • 最终结果是只用密码本 B 加密的密码
  • 但服务器从没见过解密后的密码!

2. AKE:认证密钥交换

在 OPRF 的基础上,OPAQUE 使用 AKE(Authenticated Key Exchange)完成:

  • 双方相互认证身份
  • 建立加密的会话密钥
  • 防止中间人攻击

OPAQUE 完整流程

注册阶段

Step 1-2: 客户端准备

  • 生成客户端密钥对 (pk_c, sk_c)
  • OPRF 盲化: blind = H(pwd)^r

Step 3: 客户端 → 服务器 发送 blind, pk_c

Step 4: 服务器计算

  • OPRF 计算: response = blind^key
  • 生成服务器密钥对

Step 5: 服务器 → 客户端 返回 response, pk_s

Step 6: 客户端处理

  • 去盲化得到 rwd (随机密码 wrapper)
  • 加密客户端密钥: envelope = Enc(rwd, sk_c)

Step 7: 客户端 → 服务器 发送 envelope

Step 8: 服务器存储

  • envelope (加密的客户端私钥,用 rwd 加密)
  • oprf_key (OPRF 私钥)
  • pk_c (客户端公钥)

关键点:服务器不知道 rwd,因为它无法从 blind 推出 password,所以服务器无法解密 envelope!

登录阶段

Step 1: 客户端准备

  • OPRF 盲化: blind = H(pwd)^r

Step 2: 客户端 → 服务器 发送 username, blind

Step 3: 服务器处理

  • 查找用户
  • OPRF 计算: response = blind^key

Step 4: 服务器 → 客户端 返回 response, envelope

Step 5: 客户端处理

  • 去盲化: rwd = F(key, pwd)
  • 解密: sk_c = Dec(rwd, envelope)

Step 6-7: 双向认证

  • 客户端用 sk_c 进行认证密钥交换
  • 服务器验证并建立会话
  • 双方建立安全会话

结果

  • 双方建立安全会话
  • 密码从未传输
  • 服务器从未知道密码
  • 服务器也无法解密 envelope (因为不知道 rwd)

如果密码错误

  • rwd' = F(key, wrong_pwd) ≠ rwd
  • Dec(rwd', envelope) = 乱码
  • AKE 验证失败 → 登录失败

为什么 OPAQUE 能防止离线破解?

关键在于:暴力破解必须在线进行

假设攻击者偷到了服务器数据库

攻击者获得:

  • envelope (加密的客户端私钥)
  • oprf_key? 这取决于部署方式:
    • 最佳实践:存储在 HSM(硬件安全模块)中,数据库泄露不会暴露
    • 一般部署:可能存储在配置文件或内存中,需要额外的保护措施

攻击者想暴力破解

for password in wordlist:
    blind = pow(H(password), r, N)
    response = ???  # Need server's oprf_key!
    rwd = unblind(response)
    if decrypt(rwd, envelope):
        print("Found!")

卡在第 3 步:无法独立计算 OPRF 结果,需要服务器的 oprf_key

攻击者的唯一选择:假装正常用户,向服务器发起登录请求

for password in wordlist:
    response = server.login(username, blind)  # online request
    if login_success:
        print("Found!")

但是

  • 每次请求都有网络延迟 (~100ms)
  • 服务器会限流 (每分钟 5 次)
  • 连续失败会锁定账户
  • 服务器会记录并报警

1000 个密码需要 3+ 小时,并触发安全警报。对比离线攻击:1000 个密码只需 0.00001 秒。

这就是"离线变在线"的威力!

这就是 OPAQUE 的革命性突破:把暴力破解从"离线"逼到"在线"。

SRP vs OPAQUE 终极对比

特性SRPOPAQUE
密码不传输
服务器不知道密码
防网络监听
防服务器数据库泄露⚠️ 可离线破解✅ 只能在线破解
实现复杂度中等较高
标准化程度RFC 5054(较老)IETF 草案(最新)
量子计算抵抗可升级

OPAQUE 的代价

天下没有免费的午餐,OPAQUE 的强大安全性也有代价:

  1. 实现复杂:需要实现 OPRF,比 SRP 更复杂
  2. 计算开销:每次登录需要额外的 OPRF 交互
  3. 生态不成熟:相比传统方案,库和工具较少
  4. 服务器成本:每次登录都需要服务器参与计算

谁在使用 OPAQUE?

虽然 OPAQUE 还比较新,但已经开始被采用:

  • WhatsApp:端到端加密密钥的备份恢复
  • Cloudflare:探索用于身份验证服务
  • Signal:考虑用于账户恢复
  • 企业安全系统:高安全需求场景

未来展望

OPAQUE 代表了密码认证的未来方向:

安全性演进时间线

年代方案安全特点
1990s明文存储裸奔
2000s加盐 MD5/SHA彩虹表防护
2010sArgon2慢哈希 + 内存硬化
2015+SRP密码不传输,但仍可离线破解
2020+OPAQUE防离线破解,服务器零知识

发展趋势

  1. 从"存储安全"到"传输安全"再到"计算安全"
  2. 从"被动防御"到"主动限制攻击面"
  3. 从"信任服务器"到"零知识/最小权限"

更远的未来可能是:

  • 无密码认证:生物识别 + 硬件密钥
  • 去中心化身份:区块链 + 零知识证明
  • 后量子安全:抵抗量子计算机的算法

技术细节(给好奇的读者)

OPRF 的数学原理

OPRF 基于椭圆曲线密码学:

椭圆曲线上的 OPRF

设置:

  • G = 椭圆曲线上的生成点
  • k = 服务器私钥 (随机标量)
  • H = 哈希到曲线的函数

协议流程

客户端

  1. 生成随机标量 r
  2. 密码映射到曲线点:M = H(password)
  3. 盲化(标量乘法):M' = r × M
  4. 发送 M' 给服务器

服务器

  1. 用私钥计算:Z = k × M' = k × (r × M) = r × (k × M)
  2. 返回 Z 给客户端

客户端

  1. 去盲化:N = (1/r) × Z = (1/r) × r × (k × M) = k × M(r 被消掉了!)
  2. 输出:H'(password, N) 作为最终的 OPRF 输出

安全性保证

  • 服务器只看到 M’ = r×M,r 是随机的,所以 M’ 泄露不了 M
  • 客户端得到 k×M,但不知道 k
  • 只有双方合作,才能计算出正确结果

为什么服务器数据泄露不能离线破解?

OPAQUE 的分层防护

第一层:OPRF 密钥保护

oprf_key (k) 的存储方式(按安全级别排序):

方案说明安全级别
HSM (硬件安全模块)密钥永不离开硬件,所有 OPRF 计算在硬件内完成最高
隔离进程 + 内存保护使用 Intel SGX / ARM TrustZone
加密配置文件密钥用主密钥加密存储
内存中保存启动时加载,不持久化到磁盘基础

注意:OPAQUE 的安全性很大程度上取决于 oprf_key 的保护程度。如果 oprf_key 与 envelope 一同泄露,攻击者可以离线破解(虽然计算成本仍高于传统哈希)。使用 HSM 可以获得最强保护。

第二层:envelope 保护

即使攻击者拿到 oprf_key,也无法直接破解:

  • envelope = Encrypt(rwd, client_secret_key)
  • rwd = OPRF(k, password) ← 攻击者不知道 password!

攻击者必须:

  1. 猜测 password
  2. 计算 OPRF(k, guessed_password)
  3. 尝试解密 envelope
  4. 验证解密结果是否正确

每次猜测都需要完整执行这 4 步,计算成本远高于传统哈希。

第三层:在线限制

如果 oprf_key 在 HSM 中:

  • 每次 OPRF 计算需要调用 HSM
  • HSM 有物理速率限制(如 1000 次/秒)
  • 暴力破解被硬件限速

如果攻击者只有 envelope:

  • 必须向服务器发起真实登录请求
  • 受网络延迟和服务器限流约束
  • 每秒最多几十次,而非几十亿次

总结

OPAQUE 实现了密码安全的"圣杯"

密码的最高保护等级:

  • 密码不在网络传输
  • 服务器不知道密码
  • 服务器不知道密码的哈希
  • 数据库泄露无法离线破解
  • 暴力破解只能在线进行(可被限流/锁定)

核心技术:OPRF (不经意伪随机函数)

F(k, password) 需要双方合作计算:

  • 客户端知道 password,不知道 k
  • 服务器知道 k,不知道 password
  • 单方无法独立计算结果

安全性对比

方案数据库泄露后的破解难度
MD5秒级(彩虹表)
Argon2小时~天级(GPU 暴力破解)
SRP天~周级(计算量更大)
OPAQUE不可行(必须在线,被限流)

它的核心魔法是 OPRF——一种让服务器参与计算、但又不知道计算内容的神奇技术。

虽然 OPAQUE 目前还不像传统密码方案那样普及,但它代表了密码认证的未来。随着网络安全威胁越来越严峻,我们可能会看到越来越多的服务采用 OPAQUE 或类似的先进协议。

毕竟,最好的密码保护方式,就是让任何人(包括你信任的服务器)都接触不到你的密码。


系列总结:密码安全的进化之路

时间线

年代方案特点
1990s明文存储完全裸奔
2000sMD5 + 盐值可离线破解
2010sArgon2破解变慢
2020sSRP密码不传输
未来OPAQUE无法离线破解

各方案特点对比

特性明文MD5Argon2SRPOPAQUE
服务器知道密码知道知道哈希知道哈希不知道不知道
密码传输
离线破解直接看秒级小时级天级不可行
实现难度

选型建议

场景推荐方案
一般 Web 应用Argon2id(够用,生态成熟)
高安全需求(金融、医疗)SRP 或 OPAQUE
终极安全需求OPAQUE + 硬件密钥

密码安全没有银弹,但选择正确的方案,能让攻击者的成本从"几秒钟"变成"几千年"。


上一篇:SRP:证明你知道密码却不说出密码

本系列:

  1. MD5:一部血泪史
  2. Argon2:慢哈希的艺术
  3. SRP:证明你知道密码却不说出密码
  4. OPAQUE:防离线破解的终极方案(本篇)

延伸阅读:零知识证明、后量子密码学、WebAuthn 无密码认证