我正在为移动应用程序构建一个 REST API。我需要处理身份验证。据我所知,这些是有关密码存储的最佳实践。
在客户端注册
服务器端登录
客户端登录
显然,这种方法的重点是攻击者可以毫不费力地看到任何用户的盐分。这个可以吗?显然我也可以将盐存储在客户端,但是如果例如用户从另一部手机登录,他必须能够检索盐。
另一种方法是以明文形式发送密码并在服务器端处理所有的加盐和散列。我会使用 HTTPS。
这些方法中哪一种更可取?我错过了第三个吗?
最佳答案
Obviously the week point in this approach is that an attacker can see the salt for any user effortlessly.
不,弱点是您的服务器信任客户端。以下是 MSDN 对这种情况的简短而明确的看法:
You should never trust user input directly, especially if the user input is anonymous. Remember the two golden rules: never trust user input, and always check data as it moves from an untrusted to a trusted domain.
来源:Do Not Trust User Input Directly
在这里,您将用户数据从其不受信任的客户端移动到您的服务器。您需要在您的服务器上验证他们的输入。通过在客户端上执行盐的生成和密码的散列,您无法阻止任何攻击。保护服务器-客户端通信的唯一方法是使用非对称加密的安全握手 key 交换。这发生在 HTTPS 上,一旦链接是安全的,那么以明文形式发送密码与将代码发送到客户端以执行散列客户端一样危险。
如果您不使用 HTTPS 保护与客户端的连接,您总是容易受到中间人攻击。即使密码在返回您的服务器时名义上是模糊的,攻击者也可以冒充您的服务器到客户端,发送一个跳过哈希的 HTML 表单或将明文密码发送到他们的服务器。
在您的场景中暴露盐是一个额外的安全漏洞,但它在允许攻击者直接获取密码的明显漏洞旁边是次要的。如果您愿意,我可以进一步解释这种攻击,但除非密码本身得到更好的保护,否则这是一种完全没有意义的攻击;一旦发生这种情况,您就无需首先暴露盐。
回应评论,如果您确定盐是正确生成的,那么确实可以在不降低安全性的情况下公开盐。对于盐,这意味着它们有足够的长度、足够的随机性,并且在某些方案中它们是 cryptographically secure .问题是您允许客户端生成盐,这意味着,我想我们现在都同意,他们不能被信任。也许攻击者破坏了您依赖 PRNG 的外部库。可能某些用户设备的entropy pool 不足.也许他们的设备对 side-channel attacks 不安全.如果您正在制作 Android 应用程序,那么肯定有一些非常不安全的设备。在苹果的围墙花园中,这些风险可能很低,但你永远无法消除它们。
然而,就像我最初所说的那样,与您的计划的真正危险相比,这些风险微不足道。即,您正在将明文传递的散列传输到您的服务器。即使您在将其存储到数据库之前进一步对其进行哈希处理,因此 SQL 注入(inject)不能只是转储所有用户密码,您仍然容易受到中间人攻击。未加密的 HTTP 流量可以被它通过的任何路由器观察和记录。一旦攻击者观察到哈希密码,他们就可以将相同的请求重新发送到您的服务器,并被错误地验证。
关于security - 公开暴露盐是否可以接受?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28680211/