使用将明文密码存储在钥匙串上的无状态授权机制是否安全?

信息安全 验证 休息 jwt 钥匙链
2021-09-04 13:09:42

在客户端(iOS 和 Android)和服务器之间使用以下无状态授权机制是否安全?

注册

  1. 客户端提供电子邮件和密码,并将明文密码保存在iOS 上Keychain,并使用Android的一些替代方案。

  2. 如果认为用户在 DB 上创建的足够强,服务器会检查密码强度。

  3. 服务器生成 aJWT token并将其返回给客户端。令牌的过期时间为 15 分钟。

  4. 客户端存储令牌(可能在Keychain自身上)并将其包含在标头上的每个后续请求中Authorization

  5. 对于每个请求,服务器都会检查提供的令牌(检查签名和过期时间)。如果正常则处理请求,否则HTTP 401返回 an。

登入

  1. 当客户端收到HTTP 401来自服务器的信息时,这意味着需要登录。因此应用程序访问Keychain并获取电子邮件和密码并将其发送到服务器(无需用户干预)。

  2. 服务器验证提供的凭据,如果它们有效,它将重复从 3 到 5的注册步骤。

由于令牌的到期时间,如果令牌被泄露,它将在短时间内有效。

如果用户在多台设备上登录并且她从一台设备更改了密码,则其他设备将仅在短时间内保持登录状态,但存储在该设备上的清除密码Keychain将不再有效。所以需要一个新的手动登录,我认为这很好。

你看到了哪些缺点?

我一直在考虑使用刷新令牌程序来避免存储清除密码,但这增加了复杂性和其他缺点(例如:如何保证refresh token只使用一次)。据我所知,将明文密码存储在上面KeyChain是足够安全的:

钥匙串服务文档

在 iOS 中维护登录凭据的最佳方法是什么?

但我也看到了其他不建议在设备上存储密码的问题。

所以我想听听其他人对此的看法。

2个回答

你看到了哪些缺点?

我看到的缺点主要与问题中未明确说明的内容有关,而不是与明确说明的内容有关。一般来说,您没有说明您有兴趣防范哪种攻击者?攻击者窥探本地网络?本地攻击者?

客户端提供电子邮件和密码,并将清除密码保存在 iOS 的钥匙串上,并使用 Android 的一些替代方案。

好的,所以让我们假设我们不担心已经盗用我们手机的本地(同一台机器)攻击者/进程。如果我们担心这种类型的攻击,我们还可以使用物理 MFA 设备(RSA fob 或其他)。在这种情况下,我并不特别担心手机上的静态数据......

如果认为用户在 DB 上创建的足够强,服务器会检查密码强度。

密码是如何从客户端到服务器的?如果它通过 https 从客户端到服务器,那么事情应该没问题。如果它是未加密发送的,那是一件坏事

服务器如何进行检查?检查的密码是什么服务器不应存储密码的明文副本,而服务器应仅存储密码的加密强哈希(仅使用 bcrypt)。

另外,服务器每次都在做强度检查吗?为什么?只需散列并与存储的散列进行比较。

服务器生成 JWT 令牌并将其返回给客户端。令牌的过期时间为 15 分钟。

同样,所有传输中的数据都应该加密,当然包括 JWT 令牌。根据更新,我们使用的是 HTTPS,因此只要 TLS 通道确实安全,就不会有问题(因为我们忽略了上面的本地攻击者)。

另一方面,如果 JWT 令牌有可能被盗,则需要考虑其他一些因素。例如,您应该确保用于签署 JWT 令牌的密钥足够复杂,以免被暴力破解。

登入

当客户端从服务器接收到 HTTP 401 时,这意味着需要登录。因此应用程序访问钥匙串并获取电子邮件和密码并将其发送到服务器(无需用户干预)。

客户端只连接到一台已知的服务器?服务器是如何识别的?只是通过域名吗?有人劫持域或弄乱主机文件是什么?另外,如果有一个中间人发回 401,他会像服务器一样收到电子邮件和密码吗?


更新:根据评论,正在使用 HTTPS。

因此,客户端和服务器使用通过 TLS 保护的通道进行通信。服务器(可能由您设置)向客户端发送证书。该证书包含识别服务器的信息以及服务器的公钥。但是,您没有理由信任此证书,除非它由您信任的一方签名(并且您已经将其证书嵌入到客户端设备信任存储中,用于检查签名)。例如,服务器证书可能被 MITM 攻击者截获和替换。

因此,为了真正拥有一个安全的 HTTPS 通道,您需要由客户端机器已知并信任的第三方签署的服务器证书。例如,对于 Apple,有一个受信任方列表 ( https://support.apple.com/en-us/ht204132 )。

由于您还(可能)编写客户端应用程序,您还可以在应用程序本身中嵌入已知证书或公钥,并根据嵌入证书确认服务器证书。这称为证书固定。

您还可以考虑使用 HTTP Strict Transport Security 来进一步提高应用程序的安全性。

这是一个问得很好的问题,正如问题本身所阐述的那样,即使是专家在绝对/抽象的安全框架的背景下也会有不同的意见。

微妙的现实当然是没有“绝对安全”,只有不同程度的不安全,其范围可能或多或少适合任何给定的特定情况。

在没有其他信息的情况下,一些有助于头脑风暴/威胁建模的起点问题:

  • 这些凭据保护哪些数据?

    在频谱的一端,应用程序可以是一个游戏,保护非敏感游戏状态的凭据。另一方面,凭证可以保护敏感的医疗信息。

  • 你的用户是谁?

    您的用户是否可能在许多服务(包括您自己的服务)中使用相同的密码?

    您的用户是否可能是某个可识别群体的成员,该群体或多或少会受到其设备被入侵/搜索/克隆的影响(例如记者、高级公司职员)?

  • 作为妥协的结果,个人用户和您的社区可能会发生什么?

    在此应用程序下危害一个用户帐户的行为者能否危害其他用户、窃取金钱或执行其他一些永久性的、昂贵的损害?

你明白了。

另一个想法是,从根本上说,密码是一种特别强大的凭证,预计可以随时随地在任何设备上使用。

将密码存储在设备上的一种替代方法是生成一个长期的设备特定令牌,将其保存在设备上而不是密码上,并仅用于从该设备重新进行身份验证。此令牌不必是单次使用的“刷新”令牌 - 有时应用程序会多次对密码进行哈希处理并使用它。

当然,支持任何额外的身份验证方案都需要额外的复杂性。情况可以帮助确定它是否值得。在更复杂的情况下,折衷方案可以具有可能性估计和损失估计,以及开发、维护和支持成本范围,蒙特卡罗方法可用于帮助提高对复杂性的单个位是否提供保护的直觉——通过降低风险和损失——这可能是值得的长期成本。

祝你好运!