在客户端进行密码哈希和用户认证是否可行?

5
我经常制作小型网站,并在SQL Server数据库中使用内置的ASP.NET成员资格功能,使用默认的“哈希”密码存储方法。
我想知道是否有一种方法可以通过在客户端上对密码进行哈希处理而不使用SSL以明文传输用户密码。
我意识到这只适用于启用了Javascript的用户。
或者...可能,这将是Silverlight的一个很好的内置功能(这是Silverlight路线图中的内容吗?)
编辑: 我还在寻找“安全程度”。也就是说,如果有一种方法比简单地发送明文密码更有优势,我想知道它们是什么以及原因是什么。
我知道有很多人会做具有登录功能的小型网站(例如家庭网站或志愿者为当地烹饪俱乐部制作网站),并且不认为购买SSL证书是必要的。

3
这种方式相比于明文传输更加安全在哪里?您仍然会将数据暴露给可能被用来破解用户账户的攻击者。 - Adamski
正如Adam所说,攻击者可以获取用户发送的哈希值,并使用相同的哈希值进行身份验证。 - Tom Mayfield
2
服务器必须为每个请求提供唯一的盐。 - Landon Kuhn
@Adamski - 我不确定这种方法比明文更安全...所以才会问。下面提到的一个好处是,对于不重要的网站(例如当地烹饪俱乐部),用户避免了发送他们的密码明文,因为对于许多用户来说,这个密码与他们用来访问电子邮件地址的登录密码相同。 - Feckmore
这可以防止中间人窃取密码并稍后使用,但无法防止中间人窃取身份验证并立即使用。 SSL(如果我没记错的话)通过使用您计算机上的预先存在的密钥作为测试的一部分来保护此类攻击(DNS安全漏洞意味着此保护存在缺陷),以确保服务器是其所说的那个而不是中间人欺骗的服务器。 - Brian
6个回答

6
这个想法在安全方面是不好的。如果你发送一个不带SSL的表单,其中包含哈希密码,那么任何捕获流量的人都可以登录。你的javascript必须产生一些指示成功的东西(重定向、传递给服务器的令牌等)。无论它是什么,监听器现在都可以在没有适当身份验证的情况下重新创建它。
SSL有其存在的原因,是由尝试了许多其他Web身份验证方案的人构建的。与编写自己的安全身份验证方案相比,使用证书更安全且更便宜,而这种方案不需要加密。
为了清晰起见添加说明:
仅客户端哈希并不安全。假设我有一个包含以下输入的表单
<form action="signin.whatever" method="post">
<input type="text" id="txtUser">
<input type="text" id="txtPass">
<input type="hidden" id="hiddenHash">
<input type="submit" onclick="hashAndSubmit()">
</form>

hashAndSubmit()会将密码哈希并放入hiddenHash,同时清空密码字段。如果我嗅探到您的提交并看到以下字段:

txtUser:joeuser
txtPass:
hiddenHash:xxx345yz   // hash result

作为攻击者,我只需要这些信息。我使用你的用户和哈希值构建一个表单,然后就可以开始攻击了。重放攻击不需要密码。

要解决这个问题,你必须考虑一次性盐值或其他方案。所有这些方案都比 SSL 更加昂贵(别忘了开发时间)和风险更高。在采取这样的措施之前,先问一个问题...

我是否比 SSL 加密多年的公共测试更可靠?


为什么Javascript(或其他客户端脚本)必须指示成功呢?为什么不能只将哈希密码发送到服务器进行比较,而不是发送明文密码进行服务器端哈希,然后再进行比较呢? - Feckmore
如果你在客户端进行哈希处理,那么密码就不再重要了,因为攻击者可以嗅探到哈希后的密码并进行重放攻击。如果你在客户端进行身份验证,那么你只需要回复成功令牌。无论哪种方式,你都会面临问题。 - Tim Hoolihan
这不仅仅是“我是否信任自己”,更多的是可能我真的对我没有听说过的解决方案一无所知...所以我在问。而且,我对“安全程度”也很好奇,不仅仅是最终安全性是什么(正如我在更新中所提到的)。 - Feckmore
为了消除我丰富的无知,您提到的重放攻击是否可以通过跟踪主机名或其他识别会话数据来缓解?还是这也存在不安全性问题? - Feckmore
任何类似的东西都会很有帮助,特别是如果你从 IIS 管道中获取而不是表单变量。然而,中间人攻击和欺骗可能会发生。我并没有意味着无知或听起来很严厉,如果我这样做了,对不起,我只是传达所学到的教训。 - Tim Hoolihan
不,你并没有暗示无知,我只是喜欢高估自己的无知...如果这可能的话。虽然我同意你的答案,但出于保存的考虑,我选择@jrista的答案,因为我认为它最直接地回答了问题,然后指出了缺点。 - Feckmore

6
这是完全可能的。这实际上就是Kerberos身份验证所做的,只是添加了一些特殊的内容。要确保您的身份验证机制是安全的,您需要以下内容:
  1. 客户端和服务器上都有一个共同的哈希算法。
  2. 在服务器上生成并与客户端共享的一次性盐值。
  3. 存储在数据库中的原始密码。
要通过哈希代码安全地验证用户身份,以避免在网络上传输实际密码,请首先在服务器上生成一个随机的、单次使用的盐值。将此盐值发送到客户端,并从用户输入的加盐密码版本生成一个哈希代码。将结果哈希代码发送到服务器,并将其与从存储密码的加盐版本生成的哈希代码进行比较。如果比较失败,则丢弃盐值,重新生成新的盐值,并重复该过程。
单次使用盐的原因是防止任何人监听会话并捕获用户密码的哈希代码,而使用哈希代码比较时,它与拥有密码本身一样好。
请注意,您需要保存原始密码,不能在服务器上对其进行哈希处理并将哈希保存在数据库中。如果您需要确保存储在数据库中的密码也是安全的,则需要在存储之前对其进行加密。我相信ASP.NET成员资格提供程序允许您存储加密密码,但是,如果您真的希望拥有一个安全的身份验证机制,难以被黑客破解,那么我建议完全自己处理密码存储和检索。
最后,应该注意,如果在身份验证期间使用SSL加密连接,则不需要使用这样复杂的密码传输机制。
参考文献(对于从未听说过Kerberos或SRP的人): http://en.wikipedia.org/wiki/Kerberos_(protocol) http://en.wikipedia.org/wiki/Secure_remote_password_protocol

1
不要重新发明身份验证协议,重复使用已经建立的协议。 - Remus Rusanu
1
有人可以解释一下为什么这个被投票否决了吗?这是一个完全有效的身份验证实践,已经在许多系统上使用了几十年。 - jrista
@Remus:这不是一个新协议,而是一个已经被广泛应用的协议。它是Kerberos的一部分,可以在不安全的网络中实现安全认证。http://en.wikipedia.org/wiki/Kerberos_(protocol) 密码哈希机制称为SRP,即Secure Remote Password protocol。http://en.wikipedia.org/wiki/Secure_remote_password_protocol - jrista
从您自己的链接中查看缺点。那是否看起来像是适用于互联网客户端的好列表?时钟要求呢?http://en.wikipedia.org/wiki/Kerberos_(protocol)#Drawbacks - Tim Hoolihan
@Tim:同意,正如我在原帖中最后一条评论所指出的那样,如果使用SSL,这将是不必要和过于复杂的。我试图让自己回答人们的问题,而不管我个人对这个主题的看法如何。虽然SSL确实是更好的选择,但我不能说问问题者的要求是什么或为什么存在这些要求。提供有用的知识比因个人偏见而隐藏它更好。 - jrista
显示剩余2条评论

2
你可以这样做,但它同样不安全。问题在于有人可能会截获哈希值并重放它(就像他们可以重放原始密码一样)。我猜你是为了防止实际密码的暴露(以防他们在其他系统上使用它),但你的系统将不会更加安全。

2

您可以在客户端(使用JavaScript)实现哈希算法,并仅发送用户名和哈希结果。请注意,为了确保安全性,哈希必须使用服务器提供的字符串进行加盐处理,而且每个请求的字符串必须是唯一的。服务器仍然需要检查哈希是否正确并验证会话。


1

至少你必须使用盐来生成哈希值。否则,当被拦截时,哈希值的价值与明文密码一样“有价值” - 至少在您的网站上是这样。


1

您可以按照HTTP Digest协议发送用户名/领域/密码哈希作为POST字段。据我所知,没有内置的客户端组件或服务器端组件来生成/验证此内容,因此您必须手动完成所有操作。它还需要您的存储器存储特定的哈希格式,请参见在表格中存储密码和摘要身份验证

优点是您正在遵循经过充分分析和理解的身份验证协议。不要自己开发。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接