客户端服务器身份验证

4
我正在创建一个基于异步套接字的客户端服务器通信,我的客户端将向服务器发送用户名和密码,然后服务器将回复账户是否有效。因此,我希望保护这些步骤,以便没有人可以记录对话并将其发送给我的客户端,从而实现非法进入秘密数据。
【简化问题】如何安全地验证客户端与服务器之间的身份?
【注意】我知道SSL,但我无法支付证书费用,因此我需要一种免费的替代方案来提供客户端和服务器之间的安全通信。

你如何托管服务器应用程序?IIS? - Avada Kedavra
Kerberos?http://zh.wikipedia.org/wiki/Kerberos_%28协议%29 - DeanOC
它是一个套接字监听器... 不使用IIS。 - Roman Ratskey
1
我记得有这样一句话,自己发明服务器安全的人是傻瓜的客户。 - John Saunders
4个回答

13

一如既往,最安全的密码是服务器不知道且不会被传输的密码。因此,您可以采取以下措施:

  • 在服务器上,存储用户名、随机盐(“账户盐”)和带盐密码的安全哈希值(“服务器共享密钥”)。
  • 在登录时,首先让客户端仅传输用户名(而非密码)。
  • 服务器应该回复帐户盐(不是密码)和随机生成的会话盐(不是密码)。重要的是,服务器生成会话盐。
  • 在客户端上,使用账户盐对密码进行加盐并进行哈希处理(将其保留为“客户端共享密钥”),然后再将结果与会话盐一起加盐并再次哈希处理。将其作为身份验证令牌(不是密码)发送。
  • 在服务器上,获取数据库中的加盐哈希值,使用会话盐对其进行加盐,并对其进行哈希处理——如果与身份验证令牌匹配,则连接得到验证。(客户端已通过身份验证)

  • 如果您还想向客户端验证服务器,可以重复此过程:客户端生成盐,服务器通过加盐/哈希存储的密钥来创建令牌。

  • 如果要验证单个请求(而不仅仅是连接),请使用共享密钥对其进行加盐并哈希处理,并将其作为每个请求的身份验证字段发送。由于在有效登录的情况下,服务器共享密钥和客户端共享密钥是相同的,因此双方应该得出相同的结果,从而验证身份验证字段。

enter image description here


2
也许我读错了,但我认为 OP 是在问连接安全性。话虽如此,你所说的一切都是好的,但我仍然更愿意将这个问题外包,并让一个现有的、已知安全的库来处理它。 - Eric Fleischman
3
对我来说,这归结为概率问题。你认为OP能否像微软在CLR基础实现方面做得那么好?我持怀疑态度。 - Eric Fleischman
1
正如我所说:口味不同。我的意图并不是要说服你或者争论你的想法。对于你来说,信任第三方库可能更好;对于我来说,信任我自己或者我的开发人员编写的代码(或者由他们或我审查过的代码)更好。这两个观点都有其优点,我最后一点也不会否认你的看法。 - Eugen Rieck
@EugenRieck:你为此创建了博客文章吗? - jgauffin
不,我没有——关键是,Stack Overflow 是可搜索的,并且比我的博客具有更多的谷歌权重。你还有什么信息在这里找不到,我可以提供吗? - Eugen Rieck
显示剩余48条评论

4
我通常告诉人们,如果他们发现自己在进行加密方面的工作,那么他们就是在创造安全问题。 :) 很可能你会错过一些边缘情况。我建议依靠已经存在并且经过了严密保护的东西。
如果您正在使用托管套接字,有一个流类的版本可以为您执行加密操作(NegotiateStream)。我建议从那里开始,看看它是否能够满足您的需求,而无需自己发明。

另一方面,将加密和安全外包给第三方库(甚至可能是您无法在源代码级别上验证的库)可能需要极高的信任水平。 - Eugen Rieck
好的。我会先尝试在MSFT堆栈中使用内置的加密库(优先选择托管应用程序)。这些库非常安全,并且被其他MSFT产品使用。它们已经受到了极大的安全关注。 - Eric Fleischman
NegotiateStream足够安全吗?我可以依赖它来处理所有我的数据吗?[注]我不希望任何人在没有合法许可的情况下访问我的服务器,因为数据库将包含关键信息。我想确保客户端只连接到我的服务器。 - Roman Ratskey
我觉得我没有资格权威地回答这个问题。这取决于你的需求以及如何使用 NegotiateStream。但是我可以说,它是一个比自己构建更好的起点。 :) - Eric Fleischman
我的程序将会公开发布,我非常担心它被破解,因为它的数据库包含了关键信息,所以你必须为我提供最好的身份验证方法,以确保至少90%的客户免受任何黑客攻击。 - Roman Ratskey
对于我来说,很难以权威的身份告诉你应该做什么。这取决于你的产品是否合理,你有哪些操作系统要求,你必须使用哪些密钥,哪些用户体验假设是合理的等等。一般来说,我会寻找现成的解决方案,而不是自己开发。自己开发安全通道最终会以失败告终。你需要的是已知安全的东西。很抱歉我不能确定 NegotiateStream 是否适合你。我建议你研究一下 SSL、WCF(以及它提供的安全绑定)和其他方案。 - Eric Fleischman

0
你可以使用公钥和对称密钥的组合来确保身份验证的安全性。
首先,发送一个公钥给客户端,让他将其认证数据加密后发送。如果数据有效,然后客户端可以生成自己的公钥,并通过对方的公钥相互发送对称密钥。
类似这样的方法应该可以起作用。

0

我知道这个帖子是几年前发布的,但现在我想在这里加上我的意见。 在过去的几年中,情况已经发生了变化。这可能会对其他人有所帮助。

我不想从 Eugen 那里拿走任何东西,他做得非常好。

保护客户端和服务器之间通信的最佳方法仍然是使用 SSL/TLS 加密。您现在可以从https://letsencrypt.org/获取免费许可证。

听起来你已经搞定了 SSL,所以我建议你使用上述链接获得免费证书。

祝好运, - Andrew


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