帮助理解使用盐和散列的基本用户身份验证

信息安全 密码 验证 http
2021-08-22 09:23:29

由于某种原因,我不了解如何在客户端和服务器之间为用户执行安全身份验证。我已经阅读了很多资源,并且了解如何使用散列和加盐工具,但没有得到最终结果。

用户从向服务器发送请求的移动应用程序登录。以下是我的理解:

  1. 目标是将用户的密码发送到服务器进行身份验证,但不是以明文形式发送。为每次登录生成一个唯一的随机盐。现在,将以下两项发送到服务器:

    • 哈希(盐+密码)
  2. 在服务器端,......好吧,这就是我完全困惑的地方。我到底要在这里做什么?数据库中的密码应该如何存储——hash(password)?盐是分开存放的吗?如何验证密码?谁应该生成盐 - 服务器或客户端?这是一场混乱的噩梦!

更新

看完答案后,现在更有意义了。我将使用 SSL,但我只是想知道没有它它会如何工作。现在的问题是,会话 ID 与此相关联在哪里?

A. 假设当用户登录并通过身份验证时,服务器会创建一个新的随机会话 ID,并且此会话 ID 保存在该用户的表中,然后发送回客户端并保存在那里。对于用户发出的每个后续请求,我不是每次都发送密码,而是发送会话 ID 并确保它与用户帐户中的会话 ID 匹配。我是否需要对此进行任何散列或加密,或者它是否与通过明文会话 ID 发送并检查它是否匹配一样基本?

B. 这对你们来说是另一个非常常识性的问题,但是假设我有一个 POST url 可以做一些事情,并且需要某些字段,例如 userId = self.request.get('userId')。这个值是我的客户在发送请求时分配的。问题是,攻击者能否生成他们自己对该 URL 的请求并在该请求中为 userId 填写他们自己的值,并让请求通过?我不太确定这是如何工作的..

2个回答

在您的标题中,您在谈论基本身份验证,我假设您在谈论HTTP 基本身份验证,即浏览器提示您输入密码、编码并通过网络发送。但是,您并不能真正控制使用该方法的机制和加密。通常也不使用它,因为它的安全性较低,并且您不能添加诸如 SALT、一次性密码、验证码等内容。

很可能,您希望使用通过 POST 发送表单数据的 HTML 表单来实现基于表单的身份验证。您应该使用带有证书的 SSL/TLS 确保提交此表单以供一般公众使用。这有助于限制中间人 (MiTM) 攻击的能力,在这种攻击中,攻击者可以窃听和捕获用户名和密码。您可以使用 JavaScript 在客户端进行加密,但您仍然需要预先存储初始密码。我只在几个笔测试中看到过这个实现,但用 JavaScript 来做这样的事情并不常见。

现在,关于加盐和散列,以及类似的一切。这更多地与数据库中凭据的存储有关。通常,您会通过 SSL 保护的表单提交收到未经加密的密码。您不想将实际密码存储在数据库中,因此您对其进行哈希处理并使用哈希算法(例如bcrypt)对其进行加盐。盐+哈希使您可以存储密码而无需直接存储。哈希是一种方法,除非您使用一种称为彩虹表的技术,你将不得不暴力破解每一种可能性,直到你运行算法并得到相同的结果。使用盐会使彩虹表的使用变得更加困难,因为彩虹表必须考虑到盐,而不能只是“标准”彩虹表。

你可以有一个每个用户的盐或一个你普遍使用的盐,一个每个用户的盐会更安全。在数据库的用户表中,您将存储以下内容

  1. 用户名
  2. 哈希(盐+密码)
  3. 该用户的盐

现在,当用户再次登录时,他们会在表单中提交用户名和密码。然后,您想查看它们是否在表中,然后您:

  1. 在您的数据库中查找提供的用户名并返回哈希和盐
  2. 获取提供的用户名并使用在 1 中获得的盐重新运行散列函数以进行类似散列的操作(盐+密码在表单上提交)
  3. 如果在 2 中生成的哈希值与在 1 中从数据库中检索到的 on 匹配,那么您就知道他们提供了正确的密码

关键是不存储实际密码,并且要计算出这组随机字符映射回什么的计算成本很高(即,难以确定真正的密码)。

一些进一步的阅读

更新 OP 询问不通过 SSL 发送:

您需要在此处完成以下操作:(1) 传输中的安全数据和 (2) 静态数据的安全。我们讨论的哈希实现了静态安全。为了在传输过程中保护它,您需要确保通过网络传输的数据以某种方式加密。听起来您不想获得或无法获得 SSL 证书。这通常是最常见的方式。否则,您可以实现更复杂的编程方式,在这种方式中,您拥有自己的私钥和公钥。在使用 PGP 或类似的 JavaScript 实现将数据与您的私钥一起发送之前,您或多或少地对数据进行加密。不推荐这样做,因为您很容易搞砸它,而且它需要 JavaScript,而您的用户可能没有启用它。你仍然使用如上所述的盐渍,

算法(警告 - 需要 JavaScript 或其他客户端语言enbaled)

  1. 创建一个登录表单,不要在表单中设置提交操作 - 我们不希望通过正常方式发送信息,因为它是机密的,我们没有使用 SSL
  2. 创建一个用于提交表单的 JavaScript 处理程序,作为处理的一部分,使用您的私钥加密密码字段,然后使用 HTTP post 提交。
  3. 一旦在服务器上收到,用公钥解密
  4. 您现在已经通过网络传输了带有加密的实际密码
  5. 经常更改您的私钥-公钥对以减少妥协或逆转。
  6. 继续按照上面详述的静止固定。

更新 2 OP 继续提问以了解有关保护会话变量的更多信息:

最好将所有提交都放在 SSL 上以保护窃听。即使你散列你所有的 cookie 数据,如果我可以拦截并且我只需要将散列发回给你,好吧,如果我可以成为 MiTM,我已经拥有它。您应该使用多种因素来限制会话劫持和 CSRF 攻击。与其在这里深入细节,您可能想查看OWASP Top 10并阅读各种安全问题以及如何缓解。OWASP 是学习如何保护 Web 应用程序的顶级资源之一。

您要问的第二个问题是,如果您的服务器端应用程序在传递的用户 ID 上执行基本逻辑,这可以伪造吗?是的,使用会话管理来确定当前用户,不要让客户端在认证后告诉你他们是谁。

这篇文章,也与您提出的问题有关,可能对您有用。

通过普通 HTTP(不是 HTTPS)的身份验证很少适用。确实,什么是身份验证?可以保证某些命令确实来自它们声称的对象。授予访问权限的服务器是接受 GET 和 POST 命令并响应它们的服务器,例如通过发回机密文件。如果您担心监视发送密码的邪恶窃听者,那么您应该担心可以监视服务器响应的邪恶窃听者,即直接查看机密文件本身。“‘大量密码,我将自己征用数据”,海盗说。

因此,对于大多数实用的安全模型,您需要一个实际的数据保护系统。有一个广泛使用的协议,它被称为 SSL(用于包装 HTTP 时的 HTTPS)。SSL 不仅保护传输的数据,还验证服务器:通过验证服务器证书,客户端确定它与正确的服务器通信。在这种情况下,客户端可以通过 SSL 隧道“按原样”发送密码:因为它是在 SSL 的庇护下传输的,所以密码没有风险。

如果您不使用 SSL,那么您的身份验证工作将在实际攻击场景中化为乌有。

您仍然希望使用散列和加盐,但在服务器上,而不是在客户端上。这是一种缓解措施,以降低严重违规成为灾难性的风险(有关详细讨论,请参阅此博客文章)。由于它仅用于存储,服务器端,客户端不需要知道它是如何完成的,并且通信协议不受影响。

编辑:澄清:您需要在客户端上做散列或诸如此类的事情,只是为了防止坏人在链接上做坏事,例如监视发送的内容或修改发送的内容。通过使用 HTTP 而不是 HTTPS,您已经假设这不会发生(或者,如果您不假设,那么您在某个时候会陷入残酷的幻灭)。因此,不需要在客户端上散列任何东西。