【问题标题】:"Safely" store (on client side) tokens for reuse?“安全”存储(在客户端)令牌以供重用?
【发布时间】:2018-08-17 20:40:20
【问题描述】:

我正在尝试创建一个桌面应用程序,它将向我正在开发的网络服务发送更新。

理想情况下,应用程序只需配置一次并部署到网络共享。配置应用程序时,用户将输入用于在 Web 服务中进行身份验证的密码。之后,将创建一个令牌以用于未来的连接。

这将允许任何有权访问网络共享的计算机(即使它不是配置应用程序的计算机)只运行应用程序(将连接到网络服务)而无需输入任何凭据(因为令牌已保存)。

问题是:我应该如何保护这个令牌?

  • 我知道将其存储在客户端永远不会完全安全,但我想让某人尽可能难以访问明文令牌。
  • 我正在寻找一个最好不依赖于任何操作系统资源的答案(因为应用程序可以从不同的设备上执行)。
  • 假设我可以完全控制应用程序和网络服务器
  • 我正在使用 C# 开发控制台应用程序,但我认为这更多是一个理论问题(与任何特定语言无关)

以下是我尝试/考虑过的一些事情:

  • 使用诸如 C# 的 SecureString 之类的东西序列化令牌并将其存储在文件中:这是我提供的最好的。但是很明显,如果有人获得了密钥文件的访问权限,那么逆转是非常微不足道的。

  • This 答案建议使用 Windows Data Protection API (DPAPI)(在 C# 中,ProtectedData 类),但显然,这将只允许最初保存凭据的用户访问它们,这是行不通的因为我必须从多个用户/设备访问受保护的数据。

  • 将令牌作为参数传递给应用程序:这只会更改在哪里我要存储令牌(在批处理文件或操作系统任务上例如,调用程序),但我认为它不会使它更安全。

【问题讨论】:

  • 使用令牌和刷新令牌。这样您就可以使令牌无效。
  • @CodeCaster 我已经更新了这个问题。在这种情况下,存储令牌就像存储密码本身一样:有人可以复制它并用于连接到 Web 服务而无需进行身份验证,对吧?我想了解如何保护密码/令牌
  • 你能定义你所说的“SO-independent”是什么意思吗?对于这里的大多数人来说,最常见的扩展是 Stack Overflow,我认为你不是这个意思。不幸的是,你使用它而不定义它。
  • @Damien_The_Unbeliever 感谢您的关注。这是一个错字,我的意思是独立于操作系统(OS)。我已经更新了问题:)
  • 我上一次的编辑可能对这个问题有太大的改变,但我相信它现在最好地反映了我最初的意图。

标签: c# web-services authentication password-encryption


【解决方案1】:

由于用户不是机器的管理员(这是一个基本假设),因此有很多方法可以对她隐藏。

我的建议是:

  • 确保主应用程序在与主应用程序不同的凭据下运行 登录用户,“特殊用户”。
  • 编写另一个最终用户应用程序,仅用于设置,与此应用程序对话(使用您认为合适的任何进程间通信、TCPIP 等,可能是安全的,但我不会太在意这一点)。此应用仅用于收集凭据并将其发送到第一个应用
  • 现在,主应用程序可以在登录用户无法访问的任何地方写入令牌,但我建议使用受保护的数据,因为它非常易于使用

这里有一些图形解释:

由于使用受保护数据 (Windows Data Protection) 加密的数据只能由加密它的 Windows 用户解密,因此登录用户将无法读取“特殊用户”数据。

【讨论】:

    【解决方案2】:

    我建议使用JWT

    您的服务器将在成功验证后生成一个令牌。令牌将被发送给客户端。对服务器的每个后续调用都会将标头中的令牌发送到服务器。然后服务器将验证令牌。如果通过验证,则服务器知道客户端已通过身份验证。

    无需在客户端存储用户名/密码。

    【讨论】:

    • 如何在没有客户端存储凭据的情况下进行初始身份验证以获取令牌?
    • 我错过了您原始帖子中的要求。抱歉... JWT 可能仅在您使用令牌配置客户端时才有效。
    【解决方案3】:

    没有万无一失的方法来解决这个问题,客户端最终需要访问服务器,因此可以在客户端上拥有足够权限的攻击者。

    您描述的是OAuth2 协议的典型场景,因为您可以控制服务器。使用 OAuth2,您无法避免在客户端存储秘密,但通过将其交换为令牌,您可以保护原始密码,并且可以保证令牌非常强大(用户密码往往很弱)。

    要将令牌/密码存储在客户端上,可以在存储之前对其进行加密,但这会立即引发一个问题,即在哪里存储此加密的密钥。攻击者可以从客户端中提取它。有一些方法可以提高密钥存储的安全性。

    1. 根据您的情况,您可以考虑使用Hardware security module (HSM)。
    2. 您可以使用特定于操作系统的密钥库,就像您在 data-protection-api 中提到的那样。密钥库只能帮助保护密钥,因为它有操作系统的支持(我认为这就是您对 SO-independend 的意思?)。使用 DPAPI,您不仅可以限制对登录用户的访问,还可以将其限制为本地计算机。密钥库也可在其他操作系统上使用。
    3. 可以在每次客户端启动时向用户请求,而不是将密码存储在客户端上。这可以简化为设备的启动,然后密码可以专门保存在内存中。

    【讨论】:

      【解决方案4】:

      好吧,您无法保护客户端的任何内容。一旦它在那里,任何具有特权访问权限的人都可以看到它。

      你能做的就是让这条信息在没有其他东西的情况下变得毫无用处。

      这里最好的方法是在客户端存储一种公钥,并使用这个公钥创建一个散列来通过webservice对用户进行身份验证。

      当用户配置应用程序时,服务器发送这个应用程序存储在本地的公钥。当应用程序调用服务器时,它将使用这个公钥和一个只有应用程序和服务器知道的私钥创建一个散列。然后服务器可以使用其私钥检查哈希是否正确。

      为了提高安全性,您也可以在哈希中使用时间戳,这样它会随着时间的推移而改变并防止重复使用密钥。或者它可以发送一个新的 公钥 和每个 web 服务的答案。

      【讨论】:

      • 本地存储令牌有什么区别?如果我理解正确,您会将 public key 存储在本地,这与在本地存储 key 存在相同的问题。
      • 我假设你的意思是 signature 而不是 hash 因为 a has 对公钥和私钥没有意义;)
      • @a-ctor 不同之处在于无法对散列进行逆向工程或在应用程序之外重用相同的令牌。我同意,术语不太准确...但我的意思是在用户端本地存储一个哈希值,该哈希值取决于应用程序内部且在用户端不可见的密钥...
      【解决方案5】:

      我建议您使用IdentityServer4,因为它提供符合 RFC 的协议,并且根据 GrantType,客户端应用程序会在您的桌面应用程序的上下文中给出。

      尽管令牌是明文形式,但它在 Web 服务中受到保护,其中访问控制(令牌颁发者)通过检查客户端请求中的 Origin 和存储在数据库。

      【讨论】:

        猜你喜欢
        • 2012-10-08
        • 2021-11-16
        • 2018-03-15
        • 2020-12-21
        • 2014-09-23
        • 2013-05-17
        • 2018-11-15
        • 2015-04-20
        • 2020-09-21
        相关资源
        最近更新 更多