看到 https://v2ex.com/t/843372 ,有个疑问:
假设服务端只有 [密码] 的 hash 值
,也知道 [随机验证码]
的明文,如何在没有明文密码的情况下,验证 [密码]+[随机验证码] 整体的 hash 值
符合预期?
还可能是服务端通过 UA 或其他方式判断这是旧版系统,于是把用户输入值的后几位数裁掉,认为是验证码。但这也意味着客户端发送的不是 [密码]+[随机验证码] 整体的 hash 值
,而是这段信息的明文?在实践中这样做,是不是把数据安全完全依赖于 HTTPS 的安全性,面对 MITM 就全泄漏了?
是否存在一种 hash 算法,支持通过客户端发送过来的 hash('password'+'2fa')
的结果,和服务端已知的 2fa
这段明文,推算出 hash('password')
(用户密码的 hash 值),进而与数据库中存储的密码 hash 值进行比对?这样就不存在明文保存或传输用户密码的问题了。
1
XiLingHost 2022-03-29 02:11:22 +08:00
为什么不客户端直接传 hash('password')+plain('2fa')
|
2
Building 2022-03-29 02:13:11 +08:00
发两个 hash ,一个密码 hash ,一个(密码 + 验证码) hash 不就完了吗
|
3
dLvsYgJ8fiP8TGYU OP @XiLingHost 我是这样想的,因为是旧版系统,没法在后来推出双重验证后修改传输机制。
你说的也完全可能,那看来是存在热更新,修改了传输机制 |
4
ryd994 2022-03-29 02:53:58 +08:00 via Android 7
用户输入的密码就应该是明文(+TLS ) 传输
客户端 hash 没有意义。hash 后的内容成为了实际上的密码。如果我有能力 mitm 你的 tls ,我就有能力重放这个 hash 。结果上这个 hash 就是密码了。 就算服务端指定一个随机数做盐也还是没用。我可以 mitm 改掉你的客户端输入框,取得密码原文之后再加上盐来 hash ,再传给你。 以 TLS 可能失效为前提,那不就等于没有 TLS ,等于是明文?但是又想用某个办法来保护传输中数据,那不就是重新发明 TLS (或者打败 TLS )?这就是密码学民科啊 TLS 的安全性当然需要研究,但那是专业密码学人士的问题。你作为 app 开发者,也就是 TLS 套件的用户,需要做的只有按照推荐设置配置你的 TLS 服务,然后及时更新 TLS 软件库而已。 |
5
GeruzoniAnsasu 2022-03-29 03:02:53 +08:00 3
OP 看到浏览器登录时 post 了它的密码明文时不得吓得几晚上睡不着……
在加密信道中传输的内容怎么算「明文」,你的系统输入框还「明文捕捉」了你的密码输入不是 |
6
Zhouisme 2022-03-29 03:03:05 +08:00 via Android
我记得 Apple id 可以在密码后不空格加随机认证码。
应该是本地分割验证码和密码,毕竟后六位就一定是验证码,然后分别哈希传回。 |
7
ruixue 2022-03-29 03:40:30 +08:00
@ryd994 考虑到第三方 CDN 和网页服务器的日志有可能会不脱敏地记录完整请求,浏览器先加一层 hash 也不是说就完全无意义
服务器不储存明文密码也是有意义的,万一发生数据泄露可以减少撞库攻击的概率(只要不同的服务使用的混淆 salt 不一样),当然最好的防范措施还是要求用户一站一密 |
8
xuanbg 2022-03-29 06:25:58 +08:00
就不能 hash(hash(pw) + code)的结果传给服务端验证吗?为啥需要保存密码明文?
|
9
ZE3kr 2022-03-29 07:58:12 +08:00 via iPhone 1
你在浏览器里用纯 HTML 实现的登录,传的密码肯定是明文,去 Console 里看就能看到。因此 Chrome 、Safari 等浏览器只要遇到非 HTTPS 网站填写表单,或者是非 HTTPS 网站有密码输入框,就会警告不安全。
传输时明文不等于数据库里存明文…… > 在实践中这样做,是不是把数据安全完全依赖于 HTTPS 的安全性,面对 MITM 就全泄漏了? 是的。所以 HeartBleed 漏洞一出密码全泄漏。此外 CDN 也能看到密码,如果 CDN 出了 Bug (如 Cloudflare 之前默认开启的 HTML 压缩),密码也泄漏。为什么依然要这样做?个人觉得依赖 HTTPS 更安全,因为这部分是系统 /浏览器实现的,会经常更新,用的非常广泛。自己实现的 Hash 五花八门,未必就安全,而且还要求客户端与服务器实现一样的 hash 。一些服务器依赖的硬件加密模块客户端未必支持。而且如果此时客户端存 hash(password)服务端也存 hash(password),那就和存明文密码没有多大区别了。如果此时客户端发 hash2(password),服务端存 hash1(hash2(password)),那这又和客户端发明文密码,服务端存 hash 有啥区别?中间人拿到 hash2 一样破解你。 如果客户端设置密码的时候发明文密码,登录的时候发 hash2(password, time),能稍微安全一点,但这样还不如 2FA ,因为这样只要拿到了 password ,就能算出来要发送的结果。 |
10
Tink 2022-03-29 08:01:40 +08:00 via Android
这说明不了吧
|
11
ZE3kr 2022-03-29 08:05:17 +08:00 via iPhone
@xuanbg 这样就需要服务器存 hash(password)。这样的问题就是一旦被拖库,你就拿着数据库里拖出来的 hash(password)和数据库里 TOTP 的 Passphrase ,就能直接算出来 hash(hash(pw) + code)了……反而更不安全
相比要求传输明文密码的,你从数据库里拿出来的 hash 反推明文密码还是有难度的 |
12
ZE3kr 2022-03-29 08:06:53 +08:00 via iPhone
> 是否存在一种 hash 算法,支持通过客户端发送过来的 hash('password'+'2fa') 的结果,和服务端已知的 2fa 这段明文,推算出 hash('password') (用户密码的 hash 值),进而与数据库中存储的密码 hash 值进行比对?这样就不存在明文保存或传输用户密码的问题了。
这种事情不该交给 hash 去做,因为 hash 本身就不是加密解密用的。应该交给正经的加密算法去做 |
13
FrankHB 2022-03-29 08:15:23 +08:00 1
@ryd994 你的分析有个明显的缺陷:完全假定对凭据的攻击是机器进行的。然而攻击的原理并不一定是密码学,至少还可能是社会工程学。这包括人可读而机器不可读的口令——一个常见的应用是,根据“密码”中包含的 pattern 猜测用户设置口令的偏好(比如是否包含某种明显像是生日之类的个人可识别信息),缩小相关的其它需要碰撞的敏感信息的解空间,显著优化攻击效率。而一旦经过任何一个常规的 hash ,甚至不需要 salt ,这种 pattern 就被完全破坏,也就直接报销了一个重要的攻击向量。
|
14
lovelylain 2022-03-29 08:17:27 +08:00 via Android
可以传输 hash(password+2fa),password 在数据库是对称加密存储的,验证时先解密出明文再同样算 hash(password+2fa)
|
16
codehz 2022-03-29 09:02:19 +08:00 via Android
中间完全不传输密码的验证方案也不是没有,你们电报就是用 srp 的算法确保即使全部传输数据都被解密攻击者也无法得知原始密码((顶多暴力破解,但这种情况啥协议都防止不了)
|
17
nothingistrue 2022-03-29 09:16:22 +08:00
@ruixue #7 一、CDN 不能直接获取到明文,除非你让它获取。二、服务器记录日志不脱敏,是程序设计问题,并且在开发期就可用解决,那这个就不能用来作为运行期安全措施的论据。客户端加密或者 hash ,那是肯定有意义的,但是要不要实施这种措施,是要跟成本做对比的。当前,密码泄露的风险,真得没有客户端 hash 密码造成开发测试的不方便的成本大(服务器密文保存密码更多的是防止撞库,这也能解释为什么服务器不能只是单纯的 hash 密码,而必须先加盐再散列)。
@dLvsYgJ8fiP8TGYU 只有超高安全级别要求才会在客户端加密密码,通常都是:客户端和网络传输明文,服务器端存储散列码(密文),通过 HTTTPS 来保证网络传输阶段不被窃取。此外,就算你这个系统的安全级别是要求客户端加密密码,对于没法升级的旧系统,也得允许降级成客户端不加密的方式。 |
18
lakehylia 2022-03-29 09:39:36 +08:00
如果不想让中间人攻击拿到 TLS 传输的明文密码,那确实可以明文传输 hash 后的明文密码,服务端以 hash 后的明文密码为用户密码,但是挡不住你这个账户泄漏了。
|
19
ruixue 2022-03-29 09:41:09 +08:00 2
@nothingistrue 现在很多第三方 CDN 和负载均衡器都是在他们那边实施 SSL 卸载,方便实现缓存和页面规则,不是说想让它不获取就不获取的
不明文传输和保存用户的密码确实并没有给服务本身带来什么额外的安全性,但是却能有效降低数据泄露后用户的其他服务被撞库的风险,这对于很多常用密码走天下的用户来说是一种善意,很多服务提供者愿意提高一些成本来释放这种善意,不能说他们就是傻 |
20
julyclyde 2022-03-29 13:15:50 +08:00
你的分析是正确的
|
21
ryd994 2022-03-29 14:17:43 +08:00 via Android
@FrankHB “而一旦经过任何一个常规的 hash ,甚至不需要 salt ,这种 pattern 就被完全破坏,也就直接报销了一个重要的攻击向量。”
大家都用 md5 ,只要不加盐,还不是一样?常用密码的 md5 都可以随便查表反查了。甚至包括了键盘序列加生日和手机号等常见密码组合。 社工攻击的问题根源难道不是用户复用密码?只要这点不改,那无论你做不做客户端 hash 那永远都拦不住用户被其他网站钓鱼,再钓回你的服务。 好,就算你用加盐 hash ,那你服务端存什么?楼上已经有人解释过了,这个 hash 的结果成为了实质上的密码。 问题的根源其实是,密码登录从根本上就不是高安全的鉴权方式。安全要求稍高的服务应该用 2fa+密码策略要求定期改密码。要求更高的服务应该强制智能卡公钥登录。 银行用的 USB key 。或者完全独立的电子令牌。都是基于这个原因。 我厂的生产环境就是必须智能卡登入,而且不是日常查邮件的智能卡,而且还要在专用电脑上连专用 VPN 才能连上。要是简单的密码二次 hash 就有用,我厂的安全团队是傻吗? @ruixue 你觉得这是善意,但是这真的有益吗? 如果你后端服务器的密码库泄露了,假设你用的是前端 hash 一遍后端又 hash 一遍的做法。请问要穷举 128 位的 hash 容易还是穷举任意随机密码容易? 二次 hash 只会减小值域,不会增加熵。因为 hash 一定是单向的。 |
22
ryd994 2022-03-29 14:21:14 +08:00 via Android
@ruixue 如果你不信任你的 CDN ,你完全可以用独立域名处理登入。很多大网站包括银行都是这样做的。
需要更高安全性的部分,自己管理,和其他系统解耦。反正性能也不是最重要的因素,又不是每天都需要反复登入。这种系统有必要上 CDN 吗? |
23
angryfish 2022-03-29 14:58:27 +08:00
个人觉得旧苹果事直接明文传的密码。到了服务端再分割的。或者是,有啥动态更新的吧。
|
24
ruixue 2022-03-29 15:12:03 +08:00
@ryd994 Keep relax~ 反问句三连差点噎到我了,我们是在讨论不是在争吵,语气没必要那么盛哈,心平气和有助于身心健康^_^
Anyway ,每次出现拖库事件,在已经造成损失的前提下,用户还是更希望泄露的是加了盐的 hash 而不是明文密码吧。上面那位 V 友的意思也差不多,比方说有人在 V2EX 用的密码是 Sbkill1rQlb6xv2 ,那么假如泄露了明文密码,撞库攻击者很可能会按照规律(十步杀一人千里不留行+网站名缩写)猜测这个人在 cloudflare 用的密码是 Sbkill1rQlb6xcf |
25
ryd994 2022-03-29 15:34:29 +08:00 via Android
@ruixue 脱库的问题与是否进行客户端 hash 无关
密码当然应该 hash 储存,这是没问题的 但是基于 TLS 或者 CDN 不完全可信,来证明客户端 hash 可能有益,那前提就不应该使用不可信的 CDN 。登入系统的日志属于安全日志,本来就不应该允许非安全部门访问。 事实就是没有哪个大厂的网站在使用客户端 hash 。如果客户端 hash 真的这么有效,那大厂的安全审计为何不采用? |
26
agagega 2022-03-29 15:52:52 +08:00
如果你的信道不是 HTTPS ,那手动给密码做散列也没用,因为理论上你的 JS 文件都是可能被别人注入过的
|
27
ruixue 2022-03-29 16:56:56 +08:00
@ryd994 嗯,不明文储存密码肯定是有意义的
不过我从来没说过 TLS 是“不完全可信的”,相反,我对 TLS 的安全性充分信任,即使有可能出问题那也是在 TLS 之外,比如 CDN 、负载均衡器或网页服务器解密流量后。至于客户端 hash ,我还是觉得不能一竿子打死。像 github 和 twitter 这种大厂都出现过日志泄露明文密码的漏洞,所以也不能说客户端 hash 是完全的无用功,毕竟可以减少整个链路的攻击面,万一日志配置有误也不会造成明文密码泄露,相当于多加了一道保险 https://www.sohu.com/a/230309592_465914 https://www.sohu.com/a/230826659_175007 这些大厂之所以不这么选择可能是基于成本的考量,认为这样带来的收益远低于增加的成本,但并不能得出这么做就没有任何意义的结论 |
28
laozhoubuluo 2022-03-29 19:17:15 +08:00
@xuanbg
@ZE3kr @ruixue @lakehylia @jobmailcn 1. 实现这个在 C/S 框架下也是要改服务端的。另外要注意一个安全问题,如果是两层 hash 的模式下攻击者不拥有用户的明文密码而拥有 内层 hash(password) ,那么攻击者也可以构造一个合法登录请求,让服务器无法分辨用户是否知道密码明文,这么改相当于额外构成了一个安全隐患,本来泄露的是 hash 过的密文结果能登您这个网站了。 2. 另外按照 1 这么改的话实际上密码是不能加盐或者盐必须直接发给客户端,这样的话又拉低了密码的安全系数,所以还不如明文传输完了让服务器那边能安全的给密码加盐,加盐可以提升脱裤场景下的攻击难度,而且由于盐不一样导致泄露的 hash 是无法直接复用到其他网站的。而且当前的最佳实践是哈希算法+一个密码对应一个盐。如果不用哈希算法的话那更没意义,毕竟攻击者拿到密钥或者私钥直接就能拿到密码明文了,安全性不如当前最佳实践。 3. 如果必须要做二次加密的话,合理的方式是使用 RSA 等非对称算法,服务器发公钥给客户端,客户端用公钥加密密码、OTP 等需要加密的数据之后再传给服务器,服务器用私钥解密。这个流程相当于 TLS 握手,所以意义很小。费这么半天劲只解决了低概率的 CDN 以及开发者错误记录(正常实现是绝对不会记录的,而且如果他恶意投毒的话是没意义的,因为不管是 CDN 还是开发者都可以直接在网页里面插入自己的代码从而直接把用户输入拿到),是一个成本极高收益极低的安全防护手段。 |
29
3dwelcome 2022-03-29 19:56:54 +08:00 via Android
md5 函数分 md5_update 和 md5_final ,可是有些 hash 函数,这两个函数是同一个。
也就是说,hash(password)+hash(str) = hash(password+str) |
30
chinvo 2022-03-29 20:05:28 +08:00
月经帖了...
实际结论就是不需要前端造轮子“加密”. 依赖 TLS 保障安全性. 不信任 CDN 的话, 那 CDN 也同样有能力解码或者重放前端的“加密”或 hash, 因为对后端来说, 传递过来的值就是实际有效值. 前端 hash 之后被 CDN 或者其他中间人拿走, 一样造成和明文同样的风险. 至于日志泄漏, 纯属开发或者配置问题. |
31
ryd994 2022-03-30 00:32:34 +08:00 via Android
@ruixue 成本?我没看出这事有任何成本。不是完全在客户端实现吗?老用户可以强制下次登入改密码。
CDN 日志泄密,问题难道不是登入域名压根就不该走 CDN ? 首先,请你澄清一下你的协议。服务器储存什么形式的密码。客户端发送什么形式的密码。是否加盐。 提醒你,全加一样的盐等于不加盐。 |
32
ruixue 2022-03-30 09:56:46 +08:00
@ryd994 #17 说客户端 hash 密码造成开发测试的不方便就是一种成本,你说没有任何成本,你俩要不先打一架
至于 CDN 日志泄密,又不是只有 CDN 才会有日志安全的问题,自己的服务器也有啊。上面发的 github 和 twitter 明文密码泄露的新闻只要点开过也不会认为这两个的漏洞是出在 CDN 的日志上 客户端加盐也可以不同的账号根据算法采用不同的盐 都说了语气没必要那么盛,又是反问句三连。你平时是当领导呵斥下属习惯了还是怎么。。咄咄之势你还是留给他们吧,恕不奉陪 |
33
FrankHB 2022-03-30 13:01:10 +08:00
@ryd994 要防止撞库的自动化攻击只要避免完全一样的口令即可。能反查的仅限全文匹配的没加盐的。
而且,规模受限;比如生日这个空间不够大够放表里,那么手机号呢? 另一方面,实践中用户可能使用的简单生成策略,比如把相对容易反查的数据和某个无法预测但是攻击者可以人工推断的前后缀串接,就能让反查失效。这个也算是盐,不过是加在了用户的脑子里罢了。 如果没 hash ,这仍然是一种明显的复用而会受到威胁;不巧的是,这种编码方式实际还真是挺顶用的,最起码对大多数人来讲比全随机串好记得多。 用户为什么要复用密码?因为实现成本低。这又是因为,密码这种形式,要求用户自己实现密钥的重现。 只要 UI 上需要用户日常记忆的密码(而不是你说的所谓“高安全的鉴权方式”)的情况普遍存在,“复用”基本就是刚需。但是想要高安全的鉴权方式替代,如何普及?多出来的成本你搞定? 所以说,问题的根源并非鉴权方式不够安全,而是欠缺鉴权的服务等级,无法落实对合适的路径使用合适的鉴权机制。对不重要的账户,就应该避免要求高成本的鉴权方式,而不是逼着用户平摊鉴权成本自己搭建可能对某几个关键路径不够安全的服务。 但不重要也只是相对而言,并不是说无所谓了。所以即便有智能卡的情形你能说 hash 没用,没智能卡就弃疗的思路显然是不对的。这种情况下,有没有多一层 hash ,安全性不可能一样。 特别地,考虑到这样做的主要理由正是应付直接推高用户记忆成本的被大量滥用的密钥策略,你要是想甩锅给用户这样就是安全习惯不好,是用户的错,此路更加不通。 而如果真要提高安全性,那么只有方案也是不够的。现有基础设施无法提供的安全机制的实现,服务方也应该一并提供——比如银行可以提供 USB key ,但不应该把设计甩给用户让用户自己造一个,造不出来就后果自负。 所以有没有 hash 不可忽视的情形下,hash 应该由服务方提供而非用户自己变通。 至于“hash 的结果成为了实质上的密码”,只要被截获的信息不能被反查出明显特征,这就不是用户需要关心的。服务器用哪个 hash 都不提高用户保障安全性的成本,这才是所谓的“一样”。因为成本原因,智能卡可以没有,这种“一样”反倒是优先该有的。 |
34
FrankHB 2022-03-30 13:15:40 +08:00
@FrankHB 注:我不清楚 21L“包括了键盘序列加生日和手机号等常见密码组合”具体是指什么,但是要全覆盖,光是手机号(杠一点,其实还有国际区号)都有些难度,更不用说“特定前缀+手机号+特定后缀”的组合了。注意这些 pattern 是可以每个凭据都有变化的,没法大规模自动撞库。
|
35
FrankHB 2022-03-30 17:00:36 +08:00 2
@ryd994 “脱库的问题与是否进行客户端 hash 无关”,这显示出你的理解的偏差。
虽然不直接相关,但脱库得到的内容的使用方式可以类似,使用 hash 的动机也一致。 而这种敏感数据除了脱库还可以通过劫持客户端通信来获取(于是你说的对策反而不够用)。即便没像服务器被攻击那么瞩目;就受害者看,威力一点都不小。 对抗这种攻击,要做到攻击者本人通过唯密文攻击的方式无法分辨出敏感数据中可能带有的感兴趣的特征,至少不能一眼认出来。 至于是不是正经的加密,其实相对无关紧要,所以一个像样的 hash 都行。(当然,得别被随便能反查。) 若有这种客户端 hash ,攻击者要实现相同的效果,除非强行爆破 hash ,基本还需要多攻破客户端系统基础设施。 因为系统厂商普遍盯得比较紧,后者一般比单纯让 TLS 失效(各种意义上)难得多,或者至少没法长期利用。 使用非公开 hash 算法时,强行爆破成本很难预期。 首先,若攻击者无法获得程序取得其中的算法,这就无解。(当然,网站就弃疗好了,毕竟浏览器属于公共白嫖设施。)而想要通过攻击得到能分析的样本,也需攻破基础设施。 虽然要强行作为加密系统,这明显不符合 Kerckhoffs 原则而影响适用性,但是: (1)说了用 hash 就强调不需要加密,虽然其实加密也能用,但拿来恶心攻击者这就杀鸡用牛刀了; (2)让攻击者知难而退这种更普遍的方法论甚至就不算是密码学的原理;反倒是使安全性和加密信道的密码学强度正相关的实践,只是其中的一种特例罢了。 其次,即便有样本能逆向,非公开算法自动化手段相比查表之类可以说是极弱,光分析客户端行为就够普通攻击者喝一壶的了。 再退一步,能逆向成功甚至能直接看源码,之后怎么破还得密码分析,也根本没通解。 硬从理论角度讲,这里能保障的安全性的定义根本不同:系统的安全性不是以存在确定明文(以及加密和解密)作为前提来定义的密码系统的保密性(不论是信息论安全性还是计算安全性),而是使从信息中提取任何攻击者感兴趣的函数的计算开销的度量(若资源确定,也可以用成功概率)。 一些假设:(1)攻击成功前攻击者无法预先给出区分是否有兴趣(或度量利用价值)的算法;(2)(有兴趣的信息足够少)任意不依赖内容的选取子集符合兴趣的方法的概率现实地任意接近于 0 ;(3)人基于现实不可描述的、依赖个体对敏感信息特征识别的经验,有一定概率(使用未指定的未知算法)超越任意机器提取信息的能力,特别地,蕴含筛选出提高成功率的正确决策方法。 基于(1)和(2),任何现有机器在都不能分辨被 hash 隐藏的特征是否符合攻击者的兴趣(否则这机器得能自主定义什么叫兴趣判断什么值得继续爆破,基本就是强 AI 了);于是,结合(3),确定时间内,攻击的成功严格依赖于人。 那么 hash 的作用就是专门欺负人:消除特征,添加噪音,让人肉攻击者的经验失效,概率无限接近于 0 ,成功提取信息的代价任意地大,从而实现不可攻击。 是不是值得保障这种安全是另一回事,但这种安全性的现实存在是确定的。(并且很容易有木桶效应。) |
36
nothingistrue 2022-03-31 09:45:57 +08:00 1
@ruixue 我接着看了你后面的对话,发现你是一种啥都往最好做的想法,俗称“烂好人”。这个想法在事情小的时候是真好人。但是,哪怕是非常小的成本,也是会富集的,当事情大的时候,啥都想做好就会变成啥都做不好,成了烂好人。客户端哈希或者加密对于小系统(或者个人)来说确实成本很微小,但是对于几十甚至几百人开发的大系统,成本富集到管理者那里就会很庞大。这个时候管理者就要做均衡了,极为重要的系统不止要做客户端密码哈希,客户端非对称加密都要上,甚至可能还要上物理证书(俗称的加密狗),但是面向大众用户的客户端,上个 HTTPS 就够了,哈希都不要做。
|