26

我正在为我的小型服务器客户端程序实现登录/身份验证系统。我想知道如何解决这个问题,我希望一如既往地从 Stack Overflow 获得一些很棒的提示/建议。我想我会这样做。

  • 客户端连接到服务器。
  • 服务器向客户端发送一个“令牌”(可能基于时间等等)
  • 客户端返回用户名和 sha1 加密密码以及令牌。
  • 服务器接收它们并根据服务器端数据库中的凭据对用户进行身份验证。
  • 令牌现已验证,用户已使用令牌登录。

这完全是一种安全的方式吗?我认为客户端还发送一个串行密钥或类似的密钥以形成串行/令牌对,以便另一个客户端不能伪造相同的令牌(尽管令牌是由服务器端生成的)。

不需要实施细节,因为我有能力进行实施。

我的问题应该是两个问题:

  • 有什么方法可以实现带有套接字的登录/认证系统
  • 有什么方法可以保护我的客户端到服务器的连接
  • 编辑:我忘了问,因为这是一个 C++ 问题,有没有可以帮助加密/身份验证的库?

安全对我来说是一个问题,所以我想确保我做对了。

也许一些背景信息。这是一个游戏服务器,一个人用他的帐户登录并被带到一个“大厅”,在那里他可以选择一个“世界服务器”来玩。世界服务器是一个单独的进程(可能)在同一网络中的不同机器上运行。

出于这个原因,我想在此有一个会话的概念,用户登录并生成一个会话,登录服务器将会话中继到用户选择的世界服务器,以便世界服务器知道用户实际上是登录。

我认为客户端必须确认与世界服务器的会话以及所有这些,但我稍后会担心。

真诚的, 杰西

4

2 回答 2

38

您通常根本不想通过链接发送密码,即使加密也不行。通常的方法是质询-响应协议。

  1. 客户端连接到服务器,发送用户名(但不是密码)
  2. 服务器通过发送唯一的随机数来响应
  3. 客户端使用其密码的哈希作为密钥加密该随机数
  4. 客户端将加密后的随机数发送给服务器
  5. 服务器使用用户密码的正确哈希加密随机数
  6. 服务器比较两个加密的随机数

这有几个优点。首先,这意味着密码永远不会以任何形式通过链接。其次,它不受重放攻击的影响——如果攻击者记录了对话,他们以后就不能重放客户端的回复来登录,因为随机数会改变。

保护连接(即加密内容)要简单一些。通常,两者中的一个(实际上并不重要)选择一个随机数,用另一个的公钥对其进行加密,然后将其发送给另一个。另一个解密它,然后他们使用它作为对称加密的密钥来加密会话的其余部分。

库:BeecryptOpenSSL是两个明显的库。除非您有相当具体的理由不这样做,否则您可能想要使用 TLS(它比我上面概述的要多得多,包括双向身份验证,因此服务器不仅知道客户端是谁是,但客户端也知道服务器是谁,因此可以合理地验证它没有连接到可能只是收集他的信用卡号并使用它运行的其他人)。

编辑:

要验证每个数据包而无需加密所有内容的开销,您可以执行以下操作:

  1. 服务器将其公钥与质询一起发送
  2. 客户端生成一个随机数,使用服务器的公钥对其进行加密,并将其与响应一起发回
  3. 该数字是用于反模式加密的第一个数字
  4. 客户端在它发送的每个数据包中都包含一个计数器模式结果

计数器模式意味着您只需生成连续数字,然后使用正确的密钥依次加密每个数字。在这种情况下,密钥将是客户端密码的哈希值。这意味着每个数据包都将包含一个唯一的随机数,客户端和服务器都可以生成该随机数,但没有其他人可以生成。通过使用计数器模式加密,每个数据包将有一个唯一的随机数。通过从一个随机数开始,每个会话将有一个唯一的随机数序列。

为了最大限度地减少开销,您可以只发送每个数据包的一部分结果——例如,如果您在计数器模式下使用 AES,它将为您加密的每个数字生成 16 个字节的结果。每个数据包仅包含(例如)两个字节,因此您只需每 8 个数据包加密一次数字。从理论上讲,这会降低安全性——攻击者可以只尝试一个数据包的所有 65536 个可能的值,但如果您假设连接在(例如)两次错误尝试后被破坏,那么攻击者获得正确值的机会就会变得非常小(当然,您几乎可以通过控制允许的错误尝试次数和每个数据包中包含的身份验证大小来选择愿意接受的机会)。

于 2012-07-20T14:14:23.610 回答
0

如果安全性对您来说是一个大问题,请不要自己动手。您需要一个安全的套接字库。类似OpenSSL的东西。

于 2012-07-20T14:13:53.730 回答