SRP (Secure Remote Password Protocol)
背景知识:何为认证
认证是一方通过某种方式向另一方证明他是他说声称的实体的过程。有许多种认证协议,有的简单,有的复杂,有的能对抗攻击者的攻击,但所有的认证协议可以分为 3 大类(摘自这里):
Something the user knows (passwords, PINs)
Something the user has (ID cards, smartcards)
Something the user is (voiceprint identification, retinal scanners).
有的系统会通过使用其中一种方式,或组合多种方式,但目前通过密码来完成认证是最常见的方式。保护密码至关重要,那么如何才能确保密码的安全呢?
为什么需要 SRP
传统的基于用户名-密码的应答(challenge-response)协议,通常是在服务器端保存密码明文的 Hash(但很多选用的 Hash 算法并不正确),好一点的是加盐 Hash。更有甚者直接保存明文密码,或者简单使用 base64 编码,详情查看https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol。
但所有这些方式都不够安全,密码明文就不用说了,直接 Hash 通过彩虹表破解难度也不高,加盐 Hash 相对来说要好一些,但仍然可被字典攻击,而且很多网站的实现并不规范,它们所使用的盐(Salt)并不是随机的,而是使用用户名或用户 ID 来作为盐(TODO 随机的盐就能更安全吗?加盐是为了防止撞库??)。而且对被动攻击毫无抵抗力,一旦服务器被拖库,或者攻击者通过中间人攻击(https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol)拿到密码或其 Hash 值,攻击者就可以直接冒充用户访问用户资产。
我们所需要的是一种 Zero-knowledge proof (ZKP)协议,SRP 正是一种这样的协议。
SRP 是什么
SRP是由斯坦福大学于 1997 年发起开发的一种增强的密码认证秘钥交换(password-authenticated key exchange)协议(PAKE),用于解决在不安全网络环境中安全地交换密钥的问题(通俗地说,就是 client 向 server 证明它有密码,然后双方协商出一个用于对称加/解密的秘钥)。它是 ZKP(Zero-knowledge proof) 协议的一种,Server 不需要存储密码及其等价物(密码 hash),Client 可以安全地向 Server 完成认证,窃听者或中间人无法得到用于攻击的有效信息。
经过数学证明,SRP 的安全性等价于 Diffie-Hellman 秘钥交换协议,而 DH 通常被认为针对被动攻击是安全的,但在防御主动攻击方面的表现并不理想。AuCPace 和 OPAQUE 等较新的 PAKE 提供更强的安全保证。
SRP 具备以下优势:
不需要通过网络传输密码或其等价物(比如密码 Hash),即使是 Server 也不知道密码;
Server 只需为每个用户保存一个验证器(verifier),其对攻击者的价值很有限,只有通过在计算量上不可行的暴力破解才能通过它得到密码明文。不过,攻击者可以利用它来冒充 Server,所以 Server 必须妥善保管 verifier。
可抵抗主动 &被动攻击,如中间人攻击、暴力破解、字典攻击等;
不需要引入可信的第三方(如 CA 机构)即可安全地完成认证(Kerberos需要依赖第三方),而且是 Client 和 Server 的双向认证;
额外协商出一个用于加/解密后续通信数据的对称密钥 Session Key,以便让 Client 和 Server 可以在 TLS 之上传输加密数据,进一步增强安全性。
SRP 基础知识
SRP 总体上分为三个步骤:注册(Registration)、认证(Authentication)、验证(Verification)。关于后两者的区别,参考这里。
要想深入探索 SRP 的原理,首先需要掌握一些基础知识(如已掌握可跳过),包括:
离散对数问题(Discrete Logarithm problem)
迪菲 · 赫尔曼密钥交换(Diffie–Hellman key exchange)
SRP 基础数学知识
先来复习下中学的模运算和幂运算,后面会用到。
注:符号 ^ 表示幂运算。
模运算的性质
SRP 所有的运算都会模 N,所以有必要了解下模运算的性质:
(a + b) % N = (a%N + b%N) % N
(a * b) % N = (a%N * b%N) % N
(a ^ b) % N = ((a%N) ^ b) % N
后续所有的计算操作都要模 N,但为了简化表达,会省略模 N 操作。比如:
( (g % N) ^ a ) % N 会被简化记为 g^a。
幂运算的性质
SRP 中很多运算会用到幂运算,所以有必要了解下幂运算的性质:
g ^ (a + b) = g ^ (b + a) = (g^a) * (g^b)
g ^ (a*b) = g ^(b*a) = (g^a)^b
(a * b) ^ n = (a^n) * (b ^ n)
非对称加密算法
大数分解(因式分解)问题
先了解下大数分解:
a, b 是大素数,N = a * b;
已知 a 和 b,求 N 非常简单;
但如果只知道 N,求 a 和 b 就非常困难。
大数分解是 RSA 的基础。
离散对数问题
算法描述:
设 a、N、g、A 为正整数:a < N,g < N;
对于等式 A= (g^a) % N,如果已知 g, a, N,求 A 是很容易的;但如果已知的是 A, g, N,想求 a 的值,就非常困难;
也就是说,对于函数 F(a)= (g^a) % N,是单向、不可逆的。
为了对抗字典攻击,要求:
N 为素数;
N=2q+1, q 也为素数;
N 的长度至少是 1024 bits;
g 可以选择较小的素数,比如 2 或者 5。
N 和 g 的值如何选择至关重要,RFC 5054 已经列出了一些经过证明足够安全的 N 和 g 组合了。
椭圆曲线加密
离散对数可用量子计算机快速破解,更安全的是椭圆曲线加密。
// TODO
Diffie–Hellman key exchange
参考维基百科
DH 是一种非认证密钥协商协议,用于在不安全信道上安全地协商出一个对称密钥。该协议可以保证前向安全性,为其它各种认证协议提供了算法基础。
关键点:
a 和 b 是各自随机生成的,不能在网络上传输,不对外暴露;
g 和 N 是双方协商的,可对外暴露;
A 和 B 也可对外暴露;
D-H 密钥交换的特点:
通过网络窃听拿到所有传参,也无法通过算法逆向出密码明文;
通过网络窃听拿到所有传参,想要暴力破解密码在计算量上也不可行;
会话结束后,a 和 b 就可以丢弃,因此该算法具备前向安全性;
但可被中间人攻击:攻击者 C 可以拦截在 Alice 和 Bob 中间,伪装成 Bob 和 Alice 交流,再伪装成 Alice 和 Bob 交流。
扩展知识:
DH 是一种秘钥协商协议,双方协商建立一个相同的对称密钥,加密和解密都用这同一个秘钥。而 RSA 是一种秘钥分发协议,一方(通常是 Server 端)持有私钥,并将公钥分发给其它各方(通常是 Client 端),然后 Client 随机生成一个对称密钥,用公钥加密该对称密钥,对方用私钥解密出对称密钥,由于只有 Server 拥有私钥,可确保对称密钥不会泄露(不过签名场景要用私钥加密,公钥解密,因为签名是为了保证消息完整性,而只有一方拥有私钥,拥有公钥的却有很多方)。另外,RSA 不能保证前向安全性。
SRP 发展史
参考这里
SRP-1有漏洞,于是开发了 SRP-2,但 SRP-2 也存在一些问题,所以又开发了 SRP-3,其以另一种方式解决了 SRP-1 的漏洞,并避免了 SRP-2 的问题。
SRP-1
SRP 经过发展,目前最新版本是 SRP-6a。我们先来看看最早的 SRP-1 版本。
协议介绍
可对抗字典攻击
SRP-1 可以让窃听者无法得知 Session Key K 的值,进而也无法伪装为 Client,原因是:
窃听者能知道:
A,Z,M1
还能知道 M1 和 S 的算法,即:M1 = H(Z | K) = H( (v+B) | H(B^(a+x)) ) = H( (g^x + g^b) | H((g^b)^(a+x)) ) = H( (g^x + g^b) | H(g^(ab) * g^(xb)) )
但他除了不知道 x 之外,还不知道 a 和 b,也就是说他不知道的值有 4 个:g^x, g^b, g^(ab) = (g^a)^b, g^(xb),所以无法进行字典攻击。
SRP-1 的漏洞
但 srp-1 有两个漏洞,详见这里。
漏洞 1:中间人冒充 Server,即可字典攻击
中间人攻击者拦截 Client 请求,就能得知 A 的值;然后再冒充 Server,就可以自己生成随机数 b,进而可以知道 g^b 和 g^(ab) 的值。
那么对于 M1 = H( (g^x + g^b) | H(g^(ab) * g^(xb)) ),唯一不知道的只有 x,所以可以进行字典攻击,就有可能计算得到 K 和 M1 的值,进而伪装为 Client。
漏洞 2:Server 被拖库,攻击者可以冒充 Server/Client 完成认证
假设 Server 被拖库,攻击者能冒充 Server 比较好理解,因为攻击者已经知道真实 Server 所知的所有信息,比如 g^x, N, g, s 的值,就可以拦截 Client 请求,冒充 Server 与 Client 通信,Client 是没有能力发现的。注:最新协议 SRP-6a 也没有解决这个问题,所以保护好 Server 数据至关重要。
但是攻击者还可以伪装成 Client 来完成认证,而 Server 发现不了,就没那么好理解了。这是因为攻击者已经知道了 v=g^x 的值,可以在不知道密码的情况下就计算出与 Server 端一样的 S 和 K,进而计算出 M1,具体过程如下(参考):
该漏洞本质上是构造出一个特殊的 A 值,使得 S 的计算过程退化为 B^a,而 a 是攻击者自己生成的,B 是 Server 发送给攻击者的,所以攻击者可以计算出与 Server 一样的 S 值。
SRP-2
协议介绍
上面分析过,攻击者拖库后,之所以能伪装为 Client 骗过 Server,是因为攻击者找到了一个特殊的 A 值,可以将计算 S 的算法退化为 B^a。既然如此,那就修改计算 S 的算法,不直接使用 A 值,而是使用 A^2 来计算,修改后协议就是 SRP-2。
协议过程如下图所示:
SRP-3
协议介绍
为了解决 SRP-1 的漏洞 2,在 SRP-2 的基础上再掺入另一个随机扰乱参数(Random scrambling parameter) --- u,以减少被拖库后的危害。新的协议就是本节要介绍的 SRP-3。
但 SRP-3 只能防止在 g^x 被泄露后,攻击者冒充 Client,不能防止攻击者冒充 Server。
不足之处
遭受 "two-for-one" 密码猜测攻击
Server 在向 Client 发送消息前,必须先收到 Client 的消息
SRP-6a 已经解决了这两个问题。
SRP-6a
SRP-6, which fixes "two-for-one" guessing and messaging ordering attacks, was published in 2002。该版本的协议可以确保每次登录只能猜测一个密码,有效提高了攻击难度。
srp-6a 被应用于 SSL/TLS(TLS-SRP) 及其它标准(如 EAP 和 SAML)的强密码身份认证中,同时也是 IEEE 1363.2 和 ISO/IEC 11770-4 的一部分。
注册(Registration)
步骤如下:
Group 的选择
如果攻击者可以计算运算空间 N 上的离散对数,就会对用户密码造成威胁,也会威胁到 session 会话的私密性和完整性。client 必须确保它收到的 N 值足够大,以使离散对数计算在计算量上不可行。
攻击者也可以向 client 发送一个足够确保安全的大素数 N,但其可能具有能让攻击者更容易计算的特殊格式。如果 client 使用该 N 值执行后面的计算,就会对密码安全造成威胁。由于很难实时地验证某个大素数是否足够安全,client 应该只接受 RFC 5054 附录 A 中的 Group,或者只接受提前在本地配置好的、可信任的主体发送的 N。
细节
N 必须是一个大素数,且 N=2q+1, q 也为素数。g 则为一个小素数,比如 2 或者 5。RFC 5054 的附录 A 中已经列举了一些足够安全的 N 和对应的 g 值。client 和 server 从这里选就可以了,N 的值越大,越安全,但相应的计算也更耗时,需要在安全性和用户体验上做权衡取舍。如果 server 在 Server Hello 步骤返回的 Group 不在附录 A 中,但只要 client 认为该 Group 足够安全,也可以接受它。如果认为 Group 不够安全而拒绝,就返回 "insufficient_security" 以终止流程。
认证(Authentication)
流程图:
详细步骤如下:
至此,客户端 和 服务端分别都计算出了一个 session KEY。要完成认证过程,他们必须向对方证明这两个 Key 是相等的。
细节
Client Hello:
username 不存在的情况
client 向 server 发送 username,以查询对应的 Salt 和 Group 等参数时,不能把密码相关的信息(也就是 x)传给 server。如果 server 端发现 username 不存在,可以立即返回 "unknown_psk_identity" 终止流程。如果 server 想隐藏 username 不存在的事实,也可以选择稍后在第六步中返回 "bad_record_mac",以模拟密码不正确情况。
如果 server 要模拟密码不正确的情况,需要保证对于每个 userName,每次都要返回相同的 Salt s 和 Group。server 可以存储一个密钥 "seed_key", 然后每次使用 H(seed_key, "salt" | user_name) 来生成 Salt。对于 B,server 可以返回 [1, N-1] 中的任意一个随机值。server 还要注意模拟处理延迟
Server Hello
如果 client 收到的 B % N == 0,就要立即返回 "illegal_parameter" 以终止流程。
server 需要返回加密套件对应的证书
根据所选择的加密套件,有些加密套件(以 TLS_SRP_SHA_RSA 或 TLS_SRP_SHA_DSS 开头的)必须返回相应的证书,其中包含 server 的公钥,并用对应的私钥签名该消息。详见 RFC 5054 第 2.7 小节。
server 除了必须实现 TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA 加密套件,还应当实现 TLS_SRP_SHA_WITH_AES_128_CBC_SHA 和 TLS_SRP_SHA_WITH_AES_256_CBC_SHA 套件。其它的套件,也可以实现。
Client Key Exchange
client 先向 server 发送 A,server 收到后,如果判断 A % N == 0,就必须以 "illegal_parameter" 错误终止流程。
否则,client 就接着向 server 发送 M,server 验证通过后,才能向 client 发送
验证(Verification)
因为攻击者没有 K,所以无法通过客户端和服务端的验证。
注意:客户端必须先向服务端证明它拥有 K,如果服务器验证失败,就要立马以 "bad_record_mac" 终止流程。
如果 client 从 server 收到了 "bad_record_mac",它需要提示用户 username 或者 password 不正确。
另外,在 Server 完成验证 Client 的 M1 之前,Server 不能向 Client 传输任何用 Session K 加密的数据,否则攻击者可以依此暴力破解,参考这里。
协议特性
如果攻击者知道了用户的 SRP verifier(比如通过某种方式窃取了 server 的 DB 文件),那么就可以伪装成真实的 server,也可以进行字典攻击破解用户密码。
攻击者也可以通过不断尝试来猜测用户密码,server 应该采取措施以避免其发生。比如限制每个 IP 或者 userName 的认证频率。
可能有多对 (userName, password) 匹配到同一个 SRP verifier,因为使用 SRP verifier 一定要小心,不要假设只会有一对 (userName, password) 与其匹配。
Hash 函数注意事项
RFC 5054 文档中使用 SHA-1 来计算几个值:
u: 阻止攻击者知道 SRP verifer 后伪装成真实用户去完成认证。
k: 阻止可以选择 Group 参数的攻击者发起 2-for-1 猜测攻击
x: 包含被 salt 混淆过的用户密码
对 SHA-1 进行密码学分析攻击只会影响它的碰撞抵抗,而不影响它的使用。如果发现针对 SHA-1 的攻击影响了其使用,应当选择使用了别的 Hash 算法的新的加密套件。详见 RFC 5054 第 3.4 节。
其它可选的 Hash 算法在这里,更大的 hash 算法会生成更大的 session key。
Client 注意事项
Client 绝不能通过网络将 password 以及 x 传输给任何其它方(包括 Server),也不能在日志中打印它们。只能将它们保存在内存中,且使用完后立马销毁;
Client 绝不能通过网络将 s, v 传输给除 Server 之外的任何第三方,也不能在日志中打印它们。只能将它们保存在内存中,且使用完后立马销毁;
开源实现
SRP 理解起来有些成本,稍有不甚理解有误的话,开发出的系统就会有安全漏洞。幸运的是,已经有很多开源的实现了:
JavaScript: https://github.com/mozilla/node-srp
Go: https://github.com/1Password/srp
JavaScript: https://github.com/simbo1905/thinbus-srp-npm
参考文章
目前最新版的 RFC 文档:https://datatracker.ietf.org/doc/html/rfc5054
http://srp.stanford.edu/design.html
https://pythonhosted.org/srp/srp.html
https://blog.allenchou.cc/post/srp/
https://medium.com/swlh/what-is-secure-remote-password-srp-protocol-and-how-to-use-it-70e415b94a76
http://srp.stanford.edu/ndss.html
https://blog.amis.com/srp-1f28676aa525
版权声明: 本文为 InfoQ 作者【Geek_44385e】的原创文章。
原文链接:【http://xie.infoq.cn/article/05f459de8114cacaf6e9b702c】。未经作者许可,禁止转载。
评论