众所周知,应该使用一种慢速的密码哈希算法而不是一种快速的密码哈希算法来存储密码,以防止数据库受到破坏时的暴力攻击。问题在于,对于每个登录,我们还需要运行此慢速密码哈希算法,如果很多人同时尝试登录,则对于远程登录,这可能是登录服务器上的CPU负载过大。

今天晚上,我对如何解决这个问题(使用密码验证的新协议)有了一个想法:


用户键入其用户名
客户端发送用户名给服务器。
服务器向客户端发送一个盐(可能还有其他参数)
用户键入其密码
客户端从中计算出一个慢速散列(类似bcrypt)密码,使用服务器提供的盐(可能还有安全性参数,例如迭代计数)
客户端将此哈希值发送到服务器
服务器计算另一个廉价的盐化哈希(类似于SHA-2) ),然后将其与存储在数据库中的哈希值进行比较。
(可选,以避免远程强行使用和DOS:请稍等片刻,然后再将ans发送回并限制每个用户/ IP的并行连接数。)

当然,应该对通信进行加密(因为发送的哈希值是有效密码)。

(添加明显的方式来生成和存储密码。)

我假设是这样的:




第一个的输出哈希无法真正识别出来,例如没有一种便宜的方法来仅迭代第一个哈希的可能输出,而不是
所有具有此大小的字符串。如果我理解正确,bcrypt具有此属性(如果我们仅查看输出的实际ctext部分,长度为192位)。

(ZoFreX的评论似乎表明事实并非如此。
对此有任何细节吗?)

第二个散列是抗原像的,例如
找到适合给定哈希的原像的方法没有比对输入空间进行强行强制的更好的方法。

然后我们有了:


第一个(慢速)哈希避免(或减慢)蛮力/字典对密码空间的攻击。 (为避免出现彩虹表,这已加了盐。)

第二个(快速)哈希避免了以某种方式对
数据库具有读取访问权限的攻击者可以立即使用数据登录系统。 :攻击者将
需要强行破解第一个散列的(在bcrypt示例中为192位大)输出空间,以找到原映像(然后可用作密码)。

如果我们认为有必要进一步放慢速度,可以在此处使用第二个(低因数)
bcrypt代替真正快速的哈希。

由于慢速哈希是在客户端完成的,因此服务器负载不如服务器端慢速哈希那样高。 (我假设bcrypt的工作系数很高。)

这是我的问题:



已经有一个有效的协议了与此类似吗? (从评论中看,这似乎是题外话。如果您碰巧知道一个,可以随意提一下,但要专注于下一个问题。)

相比之下,该协议想法是否存在任何弱点到通常的服务器端缓慢的密码散列?


评论

我不确定这在这里是好还是在security.stackexchange.com上应该更好。有评论吗?

我要说的第一个问题(“已经有这样的协议吗?”)是security.SE的东西,而第二个问题(“这个协议是否有弱点?”)属于crypto.SE。

@PaŭloEbermann我要去security.stack ...

您为什么要给第二个廉价哈希加盐?

@CodeInChaos:我不太记得当时发明该协议的想法,但是我想这样做是为了避免用Rainbow表或类似表攻击存储的密码表。我想在这里并没有必要,但也不会造成伤害。

#1 楼

存在比您的想法更进一步的事情。查找SRP:这是一个经过密码验证的密钥交换协议;运行该协议的两方(客户端和服务器)最终得到一个新生成的共享密钥(可用于导出加密和完整性检查密钥),并对共享的静态已知秘密进行相互认证,该秘密可以是相对较低的熵(例如密码)。

在您的系统中,这意味着该密码首先以慢速(bcrypt)的形式被导出到共享机密中,然后将结果用作“密码”。 SRP的设计使得服务器仅存储相当于“密码”哈希值的内容,而不存储密码本身,因此,获取服务器数据库的副本将使攻击者无法登录。它只能使他能够对密码进行脱机字典攻击,这时最初的bcrypt使他受了重击。

PAKE协议的优点在于,它们固有地不受窃听者进行的脱机字典攻击的影响。 :该协议可以“明文”运行,这仍然不能为被动或主动攻击者提供任何学习足够的方式来闲暇时尝试“尝试”密码的方式。只有侵入服务器的攻击者才能获得此类数据,即使这样,他也没有密码(在此我们设想的设置中,密码通过bcrypt推导值)只是其哈希值。因此,无需事先建立SSL / TLS隧道。更好的是,可以将SRP用作SSL / TLS隧道的初始握手。这是标准的,而GnuTLS是它的开源实现。带有SRP的TLS的一个特别吸引人之处在于,然后就密码而言,客户端-服务器身份验证是相互的,这意味着根本没有证书。

一个可能麻烦的问题是,必须将bcrypt中的迭代次数设置为慢速(对于攻击者而言),但仍然可以容忍(在要执行bcrypt的任何计算机上)。如果您想让bcrypt在客户端上运行,并容纳各种各样的客户端,其中一些客户端可能很贫乏(例如3年前的上网本,例如我的:旧的单核Atom时钟频率为800 MHz;也可以考虑使用智能手机),那么您必须相应地调整bcrypt迭代计数。可以说,普通用户的耐心有所限制,这使您无法将bcrypt迭代次数设置为所需的最大值。另一方面,您可以为此花费100%的客户端CPU资源(客户端可能是多任务的,但用户是unitask),这可能补偿了大部分这种影响。

摘要:使用bcrypt在客户端上,然后将结果用作TLS-with-SRP中的“密码”。

评论


$ \ begingroup $
感谢您的回答。我已经以为我的想法不可能这么新:-)。
$ \ endgroup $
–PaŭloEbermann
2011年7月14日在13:14

$ \ begingroup $
我们能否使工作因数可由用户定义,以便用户可以确定每次登录花费多少工作量(以及在典型设备上等待多长时间),并获得相应的安全性? (当然,有一些合理的最小值。)
$ \ endgroup $
–PaŭloEbermann
2011年7月14日在13:16

$ \ begingroup $
@Paũlo:可以使用户定义该信息,但是此类信息将存储在服务器上,因此必须在此过程中尽早将其传输给客户端-这需要首先传输用户名,因此将是一条额外的消息,它可能导致延迟,或者是对TLS-SRP协议的修改,这(通常)是个坏主意。我建议为每个用户使用“合理的最低要求”,并在客户端中对其进行硬编码。另外,这允许在进行网络连接之前运行bcrypt-thingy。
$ \ endgroup $
–托马斯·波宁(Thomas Pornin)
2011年7月14日在13:22

$ \ begingroup $
我们是否仍需要额外的消息来将盐提供给bcrypt(假设我们不将其存储在用户设备的某些缓存中-我们也可以存储工作因子)?没有盐(或带有硬编码盐)的攻击者可以使用彩虹表,并且仅在此处尝试bcrypt的图像。
$ \ endgroup $
–PaŭloEbermann
2011年7月14日在13:32

$ \ begingroup $
@Paũlo:嗯...你是对的。除非您使用用户名(和服务器地址)作为盐,否则我以前提倡使用它,因为它不能处理密码更改。是的,您需要额外的初始消息(和响应),用户名作为请求,salt和迭代计数作为响应。
$ \ endgroup $
–托马斯·波宁(Thomas Pornin)
2011年7月14日在13:48

#2 楼


问题是,对于每个登录,我们还需要运行此慢速密码哈希算法,如果很多人同时尝试登录,则对于远程登录,这可能是登录服务器上的CPU负载过大。 />

这不是问题。是的,bcrypt的速度很慢-但这与SHA之类的东西相比非常快!应该有可能找到适合您的散列的工作因数,该因数可以使登录快速完成,但对于任何想要强行使用数据库的人来说,仍然会在工作中投入很大的精力。请记住-入侵所需的哈希操作数量将比您网站的正常运行量大得多。

关于您的想法,通过在客户端进行哈希操作,您将获得哈希成密码。如果攻击者破坏了您的数据库,他们只需要突破快速的SHA-2哈希即可找到值,使得SHA-2(value)=存储在数据库中的哈希。然后,他们可以在登录过程中发送该值,而只是声称由于对实际密码运行慢速散列算法而拥有了该散列。

但是,使用某些东西的整个要点就像bcrypt一样,它可以减轻攻击者拥有您的数据库的攻击-您所建议的方案不再提供保护。

重申一下:他们不需要检索用户的实际密码,也不需要为了进入帐户,需要经历bcrypt哈希过程-所以是的,通过在客户端进行哈希可以使攻击变得容易得多。

评论


$ \ begingroup $
关于速度缓慢:如果我想象服务器上有数百万个用户,则所有用户一次登录的时间与蛮力地平均一个用户的时间相同(如果他们没有)密码太好),无论工作因素如何。
$ \ endgroup $
–PaŭloEbermann
2011年7月14日在12:03

$ \ begingroup $
关于您,您正在将该哈希值转换为密码:是的。但是这个有效的密码空间足够大(假设足够的哈希输出长度),使得强行使用它是不可行的。 (当然,这假设第二个哈希算法仍然是安全的(例如,没有快速的preimage攻击要比蛮力强),即使它很快)。
$ \ endgroup $
–PaŭloEbermann
2011年7月14日在12:08

$ \ begingroup $
关于速度:目前,您在登录时对密码进行哈希处理的速度非常快,以至于加载零。如果将其增加到甚至增加整个服务器负载的1%,您将使攻击者同时入侵帐户的速度降低几个数量级。这是一个明显的胜利。对于Web应用程序而言,散列密码是一件很小,容易且相对少见的事情,我绝对拒绝相信任何网站都需要SHA-1或MD5的全速运行。
$ \ endgroup $
–ZoFreX
2011年7月14日在12:11

$ \ begingroup $
关于将哈希值转换为密码的原因:鉴于输入必须是有效的bcrypt哈希值的约束,我不明白为什么要用暴力方式强制SHA-1哈希值要困难得多。您仍然具有相同的发生冲突的可能性,相同数量的预期哈希密码以查看结果-您只需对输入格式设置一些任意限制。
$ \ endgroup $
–ZoFreX
2011年7月14日在12:14

$ \ begingroup $
我假设没有一种简单(例如快速)的方法来查看给定长度正确的字符串是否是密码的bcrypt哈希。即枚举所有有效bcrypt散列的最快方法是对这些密码进行实际散列。
$ \ endgroup $
–PaŭloEbermann
2011年7月14日在12:27

#3 楼

服务器需要存储从客户端收到的用户名。它容易受到DOS攻击。但是,在(可选:阻止远程暴力破解,可能要等待一小段时间再发送答案,并限制每个用户/ IP的并行连接数。)可以防止这种攻击,但是并不一定要用户名和密码分开发送。

评论


$ \ begingroup $
DOS攻击的危险与服务器端慢速哈希计算相同,不是吗?
$ \ endgroup $
–PaŭloEbermann
2011年7月14日在12:09

$ \ begingroup $
用户名和密码的单独发送是为了允许特定于用户的盐析(针对Rainbow表/字典一次攻击不同服务器上的帐户)。
$ \ endgroup $
–PaŭloEbermann
2011年7月14日在12:12

$ \ begingroup $
如果(在返回答案之前要等待一小段时间,并限制每个用户/ IP的并行连接数。)服务器端慢速散列不易受到DOS的影响,但它易受DDOS攻击。
$ \ endgroup $
–ir01
2011年7月14日在12:44