假设在我的数据库中,我存储了用盐和相当昂贵的散列(scrypt,1000 轮 SHA2 等)散列的密码。
登录后,我应该通过网络传输什么,为什么?密码或其哈希?
是否可以通过 HTTP 等未加密通道保护此类登录?
假设在我的数据库中,我存储了用盐和相当昂贵的散列(scrypt,1000 轮 SHA2 等)散列的密码。
登录后,我应该通过网络传输什么,为什么?密码或其哈希?
是否可以通过 HTTP 等未加密通道保护此类登录?
如果您从客户端传输散列,则不会提供任何安全优势,并使散列变得毫无意义:
如果用户可以通过将散列发送到服务器来登录,那么散列实际上就是密码。
如果您的身份验证协议是关于使用纯 HTTP 向服务器发送密码或密码哈希,那么这本质上是非常弱的,原因有两个:
在线监视的人可以记录客户端发送的内容。如果仅仅发送这些字节就可以访问,那么攻击者可以简单地再次发送它们。那是重放攻击。这个问题是@AviD 在他的回答中提到的。没有多少哈希可以解决这个问题。一些协议试图通过包含来自服务器的“挑战”(一个随机值,为每个连接重新创建)来纠正这个问题,与客户端上的密码一起进行哈希处理;这就是HTTP Digest 身份验证的意义所在。
即使身份验证成功,这仍然是纯 HTTP,因此之后发送的任何数据都将容易受到攻击者的窃听和更改。如果传输介质不受保护,则身份验证将仅阻止最简单的攻击者。这就是 HTTP Digest 失败的地方。
因此,您确实需要SSL(又名 HTTPS),不仅要传达密码或其中的哈希值,还要传达客户端和服务器之间对话的其余部分。
此后我假设该协议在 SSL 隧道中运行。你想使用像 bcrypt 或 PBKDF2 这样的慢散列函数是对的;请注意,还需要使用盐来防止成本分摊(例如预先计算的表)。缓慢的加盐散列用于应对密码的内在弱点。现在,您可能想要卸载客户端上的一些散列工作。这可能有效,但会引发一些实际问题:
由于密码处理必须包含一个盐,每个密码实例都有一个新的盐,因此必须将盐传送给客户端,以便客户端可以将盐包含在它执行的散列中。这增加了协议的复杂性:客户端必须首先将用户名发送到服务器,然后服务器必须将盐发送回,并且(只有这样)客户端才能开始对密码进行哈希处理。这比通常的“将用户名和密码作为一个 POST 请求发送”多一次网络往返。
慢散列是关于接受在每个密码上花费大量 CPU,因此攻击者也必须在每个密码上花费大量 CPU。但是如果消耗的 CPU 是在客户端上,那么我们就不能随心所欲地提高它,因为:1)有些客户端的 CPU 很少(比如一些便宜的智能手机或平板电脑),以及 2)Web 上下文意味着使用 JavaScript,而 JavaScript 在散列方面的性能非常糟糕(至少比 C 代码慢 20 倍)。
因此,通常的看法是在客户端上执行部分密码散列是不值得的。
这两种选择都不安全。
传输密码将使您的协议变为纯文本。传输哈希,会使您容易受到重放攻击。
APOP 是 POP 协议的登录实现。这允许协议对网络上的任何侦听器保密密码。这样做的一个缺点是客户端和服务器都需要知道纯文本的密码,因为这是共享的秘密。在协议之前客户端和服务端都有<密码>,协议通信基本是这样的:
在这里,服务器既知道魔法又知道密码,并且能够确定用户是否知道正确的密码,而不会将其暴露给任何侦听器。
最佳做法是将哈希安全地存储在数据库中,并依赖加密通道。
两者都不是,理想情况下,使用质询响应机制,然后传输该哈希,并通过 SSL 等加密安全通道完成所有这些操作。但是大多数用户不喜欢5分钟的登录时间。更重要的是,用户在使用它之前应该检查所有这些。
最终,这取决于一个人需要多少安全性,以及一个人试图保护的攻击向量,但使用 SSL 始终是一个好主意。